quarkusio/quarkus · error · OIDCException
Opaque access token can not be converted to JsonWebToken
Error message
Opaque access token can not be converted to JsonWebToken
What it means
OidcJsonWebTokenProducer converts the current token credential into a JsonWebToken. An opaque access token is not a JWT, so attempting to inject/produce a JsonWebToken from it throws this OIDCException. The producer detects the AccessTokenCredential.isOpaque() flag and refuses the conversion.
Source
Thrown at extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcJsonWebTokenProducer.java:67
@Produces
@IdToken
@RequestScoped
JsonWebToken currentIdToken() {
return getTokenCredential(IdTokenCredential.class);
}
private JsonWebToken getTokenCredential(Class<? extends TokenCredential> type) {
if (identity.isAnonymous()) {
return new NullJsonWebToken();
}
if (identity.getPrincipal() instanceof OidcJwtCallerPrincipal
&& ((OidcJwtCallerPrincipal) identity.getPrincipal()).getCredential().getClass() == type) {
return (JsonWebToken) identity.getPrincipal();
}
TokenCredential credential = OidcUtils.getTokenCredential(identity, type);
if (credential != null && credential.getToken() != null) {
if (credential instanceof AccessTokenCredential && ((AccessTokenCredential) credential).isOpaque()) {
throw new OIDCException("Opaque access token can not be converted to JsonWebToken");
}
JwtClaims jwtClaims;
try {
jwtClaims = new JwtConsumerBuilder()
.setSkipSignatureVerification()
.setSkipAllValidators()
.build().processToClaims(credential.getToken());
} catch (InvalidJwtException e) {
throw new OIDCException(e);
}
jwtClaims.setClaim(Claims.raw_token.name(), credential.getToken());
return new OidcJwtCallerPrincipal(jwtClaims, credential);
}
String tokenType = type == AccessTokenCredential.class ? "access" : "ID";
LOG.warnf(
"Identity is not associated with an %s token. Access 'JsonWebToken' with '@IdToken' qualifier if ID token is required and 'JsonWebToken' without this qualifier when JWT access token is required. Inject either 'io.quarkus.security.identity.SecurityIdentity' or 'io.quarkus.oidc.UserInfo' if you need to have the same endpoint code working for both authorization code and bearer token authentication flows.",
tokenType);
return new NullJsonWebToken();View on GitHub (pinned to e1c734241f)
Solutions
- Inject AccessTokenCredential or TokenIntrospection instead of JsonWebToken for opaque tokens.
- Use OidcUtils.decodeJwt or parse only after checking !((AccessTokenCredential) credential).isOpaque().
- Reconfigure the IdP client to issue JWT access tokens if JWT claims are required.
- Use the ID token (@IdToken) which is always a JWT, if claims from login are sufficient.
Example fix
// before
@Inject JsonWebToken accessToken; // fails for opaque tokens
// after
@Inject AccessTokenCredential accessToken;
if (!accessToken.isOpaque()) { /* parse as JWT */ } Defensive patterns
Strategy: type-guard
Validate before calling
AccessTokenCredential cred = identity.getCredential(AccessTokenCredential.class);
if (cred != null && cred.isOpaque()) {
// do not attempt JsonWebToken conversion
} Type guard
JsonWebToken asJwt(SecurityIdentity identity) {
TokenCredential c = OidcUtils.getTokenCredential(identity, AccessTokenCredential.class);
if (c instanceof AccessTokenCredential a && a.isOpaque()) return null;
return identity.getPrincipal() instanceof JsonWebToken j ? j : null;
} Try / catch
try {
return currentAccessToken();
} catch (OIDCException e) {
return null; // opaque token: use TokenIntrospection instead
} Prevention
- Check AccessTokenCredential.isOpaque() before parsing or injecting JWT types
- Prefer injecting AccessTokenCredential/TokenIntrospection when the token format is unknown
- If JWT claims are needed, configure the IdP to issue JWT access tokens
When it happens
Trigger: Injecting @IdToken JsonWebToken or calling currentAccessToken()/currentIdToken() (e.g. via SecurityIdentity or OidcTokenCredential producer) while the active access token is opaque (introspected, non-JWT).
Common situations: Applications issuing opaque reference tokens from Keycloak/other IdP injected with JsonWebToken; code that assumes all access tokens are JWTs after switching token format server-side.
Related errors
- %s type can not be used to represent JWT claims in @Singleto
- DPoP proof token signature is invalid
- Token is opaque but the opaque token introspection is not al
- ISSUED_AT_INVALID_PAST
- JWK with kid '%s' is not available
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/e103f33cc40dbbb2.
Report an issue: GitHub.