oauth2-server icon indicating copy to clipboard operation
oauth2-server copied to clipboard

Add token revocation support

Open jacobweber opened this issue 6 years ago • 6 comments

My attempt to implement a fix for #806.

  • Moved some of the validation methods from AbstractGrant into a RequestValidatorTrait trait, so they can be used by non-grant classes. This trait includes some abstract methods, to get the client repository and the grant identifier. Those could be refactored into arguments to validateClient, if that's preferable.
  • Added RevokeTokenHandler class to handle revocation. The constructor requires the refresh token repository and the public key as arguments. Uses existing repository methods for revocation.
  • Added enableRevokeTokenHandler method to AuthorizationServer to be used during setup.
  • Added respondToRevokeTokenRequest method to AuthorizationServer, to be used in a POST request, similar to respondToAccessTokenRequest. CORS support is up to the application.
  • Example setup (based on this):
// Init our repositories
$clientRepository = new ClientRepository();
$accessTokenRepository = new AccessTokenRepository();
$scopeRepository = new ScopeRepository();
$refreshTokenRepository = new RefreshTokenRepository();

// Path to public and private keys
$privateKey = 'file://path/to/private.key';
//$privateKey = new CryptKey('file://path/to/private.key', 'passphrase'); // if private key has a pass phrase
$encryptionKey = 'lxZFUEsBCJ2Yb14IF2ygAHI5N4+ZAUXXaSeeJm6+twsUmIen'; // generate using base64_encode(random_bytes(32))
$publicKey = 'file://path/to/public.key';

// Setup the authorization server
$server = new \League\OAuth2\Server\AuthorizationServer(
    $clientRepository,
    $accessTokenRepository,
    $scopeRepository,
    $privateKey,
    $encryptionKey
);

$handler = new \League\OAuth2\Server\RevokeTokenHandler($refreshTokenRepository, $publicKey);

// Enable the revoke token handler on the server
$server->enableRevokeTokenHandler($handler);
  • Example implementation:
$app->post('/revoke', function (ServerRequestInterface $request, ResponseInterface $response) use ($app) {

    /* @var \League\OAuth2\Server\AuthorizationServer $server */
    $server = $app->getContainer()->get(AuthorizationServer::class);

    // Try to respond to the request
    try {
        return $server->respondToRevokeTokenRequest($request, $response);

    } catch (\League\OAuth2\Server\Exception\OAuthServerException $exception) {
        return $exception->generateHttpResponse($response);

    } catch (\Exception $exception) {
        $body = new Stream('php://temp', 'r+');
        $body->write($exception->getMessage());
        return $response->withStatus(500)->withBody($body);
    }
});
  • You can set $canRevokeAccessTokens in the RevokeTokenHandler constructor if you want to allow access tokens to be revoked, since the spec describes this as optional.
  • If you revoke a refresh token, and the above setting is true, it will also revoke the associated access token.
  • If you revoke an access token, it will not revoke the associated refresh token, since I don't think this is possible without adding a new repository method.

jacobweber avatar Feb 08 '19 20:02 jacobweber

BTW, I couldn't figure out how to get it to pass both tests, if I have a function that sometimes returns null. The style checker wants me to change "return null" to "return", but if I do that, I get a CI error.

jacobweber avatar Feb 12 '19 00:02 jacobweber

Is there any alternative approach you can take? I am not a fan of blank returns and would prefer the code is more explicit.

For example, if token verification fails, could we use exceptions to issue an error rather than aborting the execution?

Sephster avatar Feb 13 '19 09:02 Sephster

Sure, I refactored it to avoid returning null, and just made it revoke the token right away.

jacobweber avatar Feb 13 '19 18:02 jacobweber

Is there any reason this PR is not merged? I'd like to use the revoke in one of my project

neodc avatar Oct 02 '19 13:10 neodc

@neodc right now it looks like there are merge conflicts

simonhamp avatar Oct 02 '19 14:10 simonhamp

I think this may need some re-working – it was written for 7.x, and 8.0.0 has come out since then. Not sure I'll have time right now to do it, but if you guys are still interested in merging it, I can try.

jacobweber avatar Oct 02 '19 19:10 jacobweber