public function exchange()
    {
        $code = $this->getAuthorizationCode();
        if (! $code) {
            return false;
        }

        $state = $this->getState();
        if (! $this->stateHandler->validate($state)) {
            throw new CoreException('Invalid state');
        }

        if ($this->user) {
            throw new CoreException('Can\'t initialize a new session while there is one active session already');
        }

        $response = $this->authentication->code_exchange($code, $this->redirectUri);

        if (empty($response['access_token'])) {
            throw new ApiException('Invalid access_token - Retry login.');
        }

        $this->setAccessToken($response['access_token']);

        if (isset($response['refresh_token'])) {
            $this->setRefreshToken($response['refresh_token']);
        }

        if (! empty($response['id_token'])) {
            $this->setIdToken($response['id_token']);
        }

        if ($this->skipUserinfo) {
            $user = $this->idTokenDecoded;
        } else {
            $user = $this->authentication->userinfo($this->accessToken);
        }

        if ($user) {
            $this->setUser($user);
        }

        return true;
    }