public function handleCallback(array $query)
{
$queryState = isset($query['state']) ? $query['state'] : null;
$queryCode = isset($query['code']) ? $query['code'] : null;
$queryError = isset($query['error']) ? $query['error'] : null;
$queryErrorDescription = isset($query['error_description']) ? $query['error_description'] : null;
if (null === $queryState) {
throw new CallbackException('state parameter missing');
}
$state = $this->tokenStorage->getState($this->clientConfigId, $queryState);
if (false === $state) {
throw new CallbackException('state not found');
}
// avoid race condition for state by really needing a confirmation
// that it was deleted
if (false === $this->tokenStorage->deleteState($state)) {
throw new CallbackException('state already used');
}
if (null === $queryCode && null === $queryError) {
throw new CallbackException('both code and error parameter missing');
}
if (null !== $queryError) {
// FIXME: this should probably be CallbackException?
throw new AuthorizeException($queryError, $queryErrorDescription);
}
if (null !== $queryCode) {
$t = new TokenRequest($this->httpClient, $this->clientConfig);
$tokenResponse = $t->withAuthorizationCode($queryCode);
if (false === $tokenResponse) {
throw new CallbackException('unable to fetch access token with authorization code');
}
if (null === $tokenResponse->getScope()) {
// no scope in response, we assume we got the initially requested scope
$scope = $state->getScope();
} else {
// the scope we got should be a superset of what we requested
$scope = $tokenResponse->getScope();
if (!$scope->hasScope($state->getScope())) {
// we didn't get the scope we requested, stop for now
// FIXME: we need to implement a way to request certain
// scope as being optional, while others need to be
// required
throw new CallbackException('requested scope not obtained');
}
}
// store the access token
$accessToken = new AccessToken(array('client_config_id' => $this->clientConfigId, 'user_id' => $state->getUserId(), 'scope' => $scope, 'access_token' => $tokenResponse->getAccessToken(), 'token_type' => $tokenResponse->getTokenType(), 'issue_time' => time(), 'expires_in' => $tokenResponse->getExpiresIn()));
$this->tokenStorage->storeAccessToken($accessToken);
// if we also got a refresh token in the response, store that as
// well
if (null !== $tokenResponse->getRefreshToken()) {
$refreshToken = new RefreshToken(array('client_config_id' => $this->clientConfigId, 'user_id' => $state->getUserId(), 'scope' => $scope, 'refresh_token' => $tokenResponse->getRefreshToken(), 'issue_time' => time()));
$this->tokenStorage->storeRefreshToken($refreshToken);
}
return $accessToken;
}
}