/**
  * Grants access token for request
  *
  * @param IRequest $request
  *
  * @throws \OAuth2\Exception\InvalidGrantException
  * @throws \OAuth2\Exception\InvalidRequestException
  * @throws \OAuth2\Exception\UnauthorizedClientException
  * @return IAccessToken
  */
 public function grant(IRequest $request)
 {
     $code = $request->request('code');
     if (empty($code)) {
         throw new InvalidRequestException("Parameter 'code' is missing.");
     }
     $client = $this->clientAuthenticator->authenticate($request);
     if (!$client->isAllowedToUse($this)) {
         throw new UnauthorizedClientException('Client can not use this grant type.');
     }
     $authorizationCode = $this->authorizationCodeStorage->get($code);
     if (!$authorizationCode) {
         throw new InvalidGrantException('Authorization code is invalid.');
     }
     if ($authorizationCode->getExpiresAt() < time()) {
         throw new InvalidGrantException('Authorization code has expired.');
     }
     if ($client->getId() !== $authorizationCode->getClient()->getId()) {
         throw new InvalidGrantException('Authorization code is invalid.');
     }
     $redirectUri = $request->request('redirect_uri');
     $codeRedirectUri = $authorizationCode->getRedirectUri();
     if (!empty($redirectUri)) {
         if (empty($codeRedirectUri) || $redirectUri !== $codeRedirectUri) {
             throw new InvalidRequestException('Redirect URI is missing, was not used in authorization or is invalid.');
         }
     } else {
         if (!empty($codeRedirectUri)) {
             throw new InvalidRequestException('Redirect URI is missing, was not used in authorization or is invalid.');
         }
     }
     return $this->accessTokenStorage->generate($authorizationCode->getUser(), $authorizationCode->getClient(), $authorizationCode->getScopes());
 }
 function it_issues_an_access_token(IRequest $request, IClientAuthenticator $clientAuthenticator, IAuthorizationCodeStorage $authorizationCodeStorage, IAuthorizationCode $authorizationCode, IAccessTokenStorage $accessTokenStorage, IAccessToken $accessToken, IUser $user, IClient $client, IScope $scope)
 {
     $request->request('code')->willReturn('a')->shouldBeCalled();
     $clientAuthenticator->authenticate($request)->willReturn($client)->shouldBeCalled();
     $client->isAllowedToUse($this)->willReturn(true)->shouldBeCalled();
     $authorizationCodeStorage->get('a')->willReturn($authorizationCode)->shouldBeCalled();
     $authorizationCode->getExpiresAt()->willReturn(time() + 100)->shouldBeCalled();
     $client->getId()->willReturn('id')->shouldBeCalled();
     $authorizationCode->getClient()->willReturn($client)->shouldBeCalled();
     $request->request('redirect_uri')->willReturn(null)->shouldBeCalled();
     $authorizationCode->getRedirectUri()->willReturn(null)->shouldBeCalled();
     $authorizationCode->getScopes()->willReturn([$scope])->shouldBeCalled();
     $authorizationCode->getUser()->willReturn($user)->shouldBeCalled();
     $authorizationCode->getClient()->willReturn($client)->shouldBeCalled();
     $accessTokenStorage->generate($user, $client, [$scope])->willReturn($accessToken)->shouldBeCalled();
     $this->grant($request)->shouldReturn($accessToken);
 }