{"record":{"id":"7b704decc5fe6114","repo":"thephpleague/oauth2-server","slug":"access-token-has-been-revoked","errorCode":null,"errorMessage":"Access token has been revoked","messagePattern":"Access token has been revoked","errorType":"http","errorClass":"OAuthServerException","httpStatus":401,"severity":"error","filePath":"src/AuthorizationValidators/BearerTokenValidator.php","lineNumber":132,"sourceCode":"        }\n\n        try {\n            // Attempt to validate the JWT\n            $constraints = $this->jwtConfiguration->validationConstraints();\n            $this->jwtConfiguration->validator()->assert($token, ...$constraints);\n        } catch (RequiredConstraintsViolated $exception) {\n            throw OAuthServerException::accessDenied('Access token could not be verified', null, $exception);\n        }\n\n        if (!$token instanceof UnencryptedToken) {\n            throw OAuthServerException::accessDenied('Access token is not an instance of UnencryptedToken');\n        }\n\n        $claims = $token->claims();\n\n        // Check if token has been revoked\n        if ($this->accessTokenRepository->isAccessTokenRevoked($claims->get('jti'))) {\n            throw OAuthServerException::accessDenied('Access token has been revoked');\n        }\n\n        // Return the request with additional attributes\n        return $request\n            ->withAttribute('oauth_access_token_id', $claims->get('jti'))\n            ->withAttribute('oauth_client_id', $claims->get('aud')[0])\n            ->withAttribute('oauth_user_id', $claims->get('sub'))\n            ->withAttribute('oauth_scopes', $claims->get('scopes'));\n    }\n}\n","sourceCodeStart":114,"sourceCodeEnd":143,"githubUrl":"https://github.com/thephpleague/oauth2-server/blob/9d2f6fc0a0b5aa1bb02506971d3a4ecff2c6526c/src/AuthorizationValidators/BearerTokenValidator.php#L114-L143","documentation":"Guard inside validateAuthorization(): after the JWT signature and standard constraints (expiry, audience, etc.) pass, the token's jti claim is looked up against the access-token repository and the stored token has been revoked (e.g. via refresh-token rotation, explicit revoke endpoint, or token revocation). The credential is valid JWT-wise but no longer active, so the request is denied.","triggerScenarios":"Token was revoked (logout, client revoked consent, password change, refresh-token rotation revoking ancestors) but the client keeps replaying it.","commonSituations":"User logged out and old token cached client-side; refresh token reuse triggered revocation of the family; stale token cached in a mobile app.","solutions":["Obtain a new access token (re-authenticate or use a valid refresh token).","Clear cached tokens on logout/revocation client-side.","Check isAccessTokenRevoked() implementation — a DB issue can falsely report revocation.","Verify revocation persistence and that the right token identifier (jti) is stored."],"exampleFix":"// before\n$request->getHeader('Authorization'); // reuses cached revoked token\n// after\nif ($this->tokenStore->isRevoked($accessToken)) {\n    $accessToken = $this->refreshAccessToken($refreshToken);\n}\n$request = $request->withHeader('Authorization', 'Bearer ' . $accessToken);","handlingStrategy":"try-catch","validationCode":"// can't pre-check server-side revocation; client should handle 401 by refreshing\nif ($this->localRevocationCache->contains($jti)) { $this->forceRefresh(); }","typeGuard":null,"tryCatchPattern":"try { $request = $validator->validateAuthorization($request); } catch (OAuthServerException $e) {\n  // signal the client to discard the token and refresh\n  return $e->generateHttpResponse(new Response(), 401);\n}","preventionTips":["Purge client token cache on logout and on any 401","Treat 401 as refreshable but refresh-token reuse failures as full re-login","Keep isAccessTokenRevoked backed by a reliable store (DB index on jti)"],"tags":["oauth","token-revocation","bearer-token"],"backgroundTag":"access-token-revoked","analyzedSha":"9d2f6fc0a0b5aa1bb02506971d3a4ecff2c6526c","analyzedAt":"2026-09-15T22:33:30.452Z","contentChangedAt":"2026-09-15T22:33:30.452Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}