thephpleague/oauth2-server · error · OAuthServerException
Access token is not an instance of UnencryptedToken
Error message
Access token is not an instance of UnencryptedToken
What it means
Guard inside validateAuthorization(): the string parsed from the Authorization header is a JWE (encrypted token) or otherwise not an UnencryptedToken, so its claims (such as the jti used for revocation checks) cannot be read. This server issues/accepts only signed, unencrypted JWTs, so an encrypted or opaque token presented as a bearer credential is rejected.
Solutions
- Send the standard (unencrypted JWS) access token issued by league/oauth2-server.
- Ensure the issuer doesn't encrypt tokens (JWE); use signed-only JWTs.
- Confirm the client isn't sending an ID token or refresh token in the Authorization header.
Example fix
// before
$request = $request->withHeader('Authorization', 'Bearer ' . $idToken);
// after
$request = $request->withHeader('Authorization', 'Bearer ' . $accessToken); Defensive patterns
Strategy: type-guard
Validate before calling
$jwt = substr($header, 7);
if (substr_count($jwt, '.') !== 2) throw new \RuntimeException('Not a JWS access token'); Type guard
function isUnencryptedJwt(string $token): bool { $p = explode('.', $token); return count($p) === 3 && $p[0] !== '' && $p[2] !== ''; } Try / catch
try { $request = $validator->validateAuthorization($request); } catch (OAuthServerException $e) { return $e->generateHttpResponse(new Response(), 401); } Prevention
- Send the access token, never the ID token
- Disable JWE token encryption in the issuer
- Document that only opaque-3-part JWTs are accepted
When it happens
Trigger: Client sends an encrypted token or a non-JWT opaque string that the parser accepted (e.g. a signed JWE, or a token type from a different library).
Common situations: Issuer uses JWE encryption while validator expects unencrypted JWS; client sends an ID token/session cookie instead of an access token.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Access token could not be verified
- invalid request: response_type
- unsupported grant type
- Missing "Authorization" header
- Missing "Bearer" token
AI-assisted analysis of thephpleague/oauth2-server@9d2f6fc0a0 (2026-09-15).
Data as JSON: /api/errors/888b5aeb0e56f320.
Report an issue: GitHub.
Appendix: source
Thrown at src/AuthorizationValidators/BearerTokenValidator.php:125
}
try {
// Attempt to parse the JWT
$token = $this->jwtConfiguration->parser()->parse($jwt);
} catch (Exception $exception) {
throw OAuthServerException::accessDenied($exception->getMessage(), null, $exception);
}
try {
// Attempt to validate the JWT
$constraints = $this->jwtConfiguration->validationConstraints();
$this->jwtConfiguration->validator()->assert($token, ...$constraints);
} catch (RequiredConstraintsViolated $exception) {
throw OAuthServerException::accessDenied('Access token could not be verified', null, $exception);
}
if (!$token instanceof UnencryptedToken) {
throw OAuthServerException::accessDenied('Access token is not an instance of UnencryptedToken');
}
$claims = $token->claims();
// Check if token has been revoked
if ($this->accessTokenRepository->isAccessTokenRevoked($claims->get('jti'))) {
throw OAuthServerException::accessDenied('Access token has been revoked');
}
// Return the request with additional attributes
return $request
->withAttribute('oauth_access_token_id', $claims->get('jti'))
->withAttribute('oauth_client_id', $claims->get('aud')[0])
->withAttribute('oauth_user_id', $claims->get('sub'))
->withAttribute('oauth_scopes', $claims->get('scopes'));
}
}
View on GitHub (pinned to 9d2f6fc0a0)