/** * {@inheritDoc} */ public function createTokenResponse(ServerRequestInterface $request, Client $client = null, TokenOwnerInterface $owner = null) : ResponseInterface { $postParams = $request->getParsedBody(); $refreshToken = $postParams['refresh_token'] ?? null; if (null === $refreshToken) { throw OAuth2Exception::invalidRequest('Refresh token is missing'); } // We can fetch the actual token, and validate it /** @var RefreshToken $refreshToken */ $refreshToken = $this->refreshTokenService->getToken($refreshToken); if (null === $refreshToken || $refreshToken->isExpired()) { throw OAuth2Exception::invalidGrant('Refresh token is expired'); } // We can now create a new access token! First, we need to make some checks on the asked scopes, // because according to the spec, a refresh token can create an access token with an equal or lesser // scope, but not more $scopes = $postParams['scope'] ?? $refreshToken->getScopes(); if (!$refreshToken->matchScopes($scopes)) { throw OAuth2Exception::invalidScope('The scope of the new access token exceeds the scope(s) of the refresh token'); } $owner = $refreshToken->getOwner(); $accessToken = new AccessToken(); $this->populateToken($accessToken, $client, $owner, $scopes); /** @var AccessToken $accessToken */ $accessToken = $this->accessTokenService->createToken($accessToken); // We may want to revoke the old refresh token if ($this->rotateRefreshTokens) { $this->refreshTokenService->deleteToken($refreshToken); $refreshToken = new RefreshToken(); $this->populateToken($refreshToken, $client, $owner, $scopes); $refreshToken = $this->refreshTokenService->createToken($refreshToken); } // We can generate the response! return $this->prepareTokenResponse($accessToken, $refreshToken, true); }
/** * @param ServerRequestInterface $request * @return ResponseInterface * @throws OAuth2Exception If no "token" is present */ public function handleRevocationRequest(ServerRequestInterface $request) : ResponseInterface { $postParams = $request->getParsedBody(); $token = $postParams['token'] ?? null; $tokenHint = $postParams['token_type_hint'] ?? null; if (null === $token || null === $tokenHint) { throw OAuth2Exception::invalidRequest('Cannot revoke a token as the "token" and/or "token_type_hint" parameters are missing'); } if ($tokenHint !== 'access_token' && $tokenHint !== 'refresh_token') { throw OAuth2Exception::unsupportedTokenType(sprintf('Authorization server does not support revocation of token of type "%s"', $tokenHint)); } if ($tokenHint === 'access_token') { $token = $this->accessTokenService->getToken($token); } else { $token = $this->refreshTokenService->getToken($token); } $response = new Response(); // According to spec, we should return 200 if token is invalid if (null === $token) { return $response; } // Now, we must validate the client if the token was generated against a non-public client if (null !== $token->getClient() && !$token->getClient()->isPublic()) { $requestClient = $this->getClient($request, false); if ($requestClient !== $token->getClient()) { throw OAuth2Exception::invalidClient('Token was issued for another client and cannot be revoked'); } } try { if ($tokenHint === 'access_token') { $this->accessTokenService->deleteToken($token); } else { $this->refreshTokenService->deleteToken($token); } } catch (\Exception $exception) { // According to spec (https://tools.ietf.org/html/rfc7009#section-2.2.1), we should return a server 503 // error if we cannot delete the token for any reason $response = $response->withStatus(503, 'An error occurred while trying to delete the token'); } return $response; }