quarkusio/quarkus · error · OIDCException

ID token values are not equal

Error message

ID token values are not equal

What it means

The OIDC code-flow test resource compares the token credential's raw token with the id token's raw token and throws OIDException when they differ. In the normal code-flow flow both should reference the same ID token, so inequality indicates the wrong token was attached to the SecurityIdentity — the bug class this test guards against (e.g. token refreshed/replaced or stale token state).

Source

Thrown at integration-tests/oidc-code-flow/src/main/java/io/quarkus/it/keycloak/ProtectedResource.java:133

        return configMetadata.getSupportedSubjectTypes().stream().collect(Collectors.joining(","));
    }

    @GET
    @Path("configMetadataIdTokenSigningAlgorithms")
    public String configMetadataIdTokenSigningAlgorithms() {
        return configMetadata.getSupportedIdTokenSigningAlgorithms().stream().collect(Collectors.joining(","));
    }

    @GET
    @Path("configMetadataCodeChallengeMethods")
    public String configMetadataCodeChallengeMethods() {
        return configMetadata.getSupportedCodeChallengeMethods().stream().collect(Collectors.joining(","));
    }

    @GET
    public String getName() {
        if (!idTokenCredential.getToken().equals(idToken.getRawToken())) {
            throw new OIDCException("ID token values are not equal");
        }
        if (identity.getAttribute(RoutingContext.class.getName()) == null) {
            throw new OIDCException("SecurityIdentity must have a RoutingContext attribute");
        }
        return idToken.getName();
    }

    @GET
    @Path("tenant-idtoken-only")
    public String getNameIdTokenOnly() {
        return "tenant-idtoken-only:" + getName();
    }

    @GET
    @Path("tenant-id-refresh-token")
    public String getNameIdRefreshTokenOnly() {
        return "tenant-id-refresh-token:" + getName();
    }

View on GitHub (pinned to e1c734241f)

Solutions

  1. Upgrade to a Quarkus version with the code-flow token consistency fix
  2. Ensure only one OIDC authentication mechanism applies to the request path
  3. Check token refresh/refresh-token settings in application.properties for premature token rotation
  4. Clear browser session/cookies and re-authenticate so a fresh, consistent token pair is issued

Example fix

// before
if (!idTokenCredential.getToken().equals(idToken.getRawToken())) {
    throw new OIDCException("ID token values are not equal");
}
// after (upgrade + derive both from the identity consistently)
String raw = TokenCredential.class.cast(identity.getAttribute("token")).getToken();
if (raw == null || !raw.equals(idToken.getRawToken())) {
    throw new OIDCException("ID token values are not equal");
}
Defensive patterns

Strategy: type-guard

Validate before calling

String cred = idTokenCredential.getToken();
String raw = idToken.getRawToken();
if (cred == null || raw == null || !cred.equals(raw)) {
    // token state inconsistent; re-authenticate before proceeding
}

Type guard

static boolean consistentIdToken(TokenCredential cred, IdToken idToken) {
    String a = cred.getToken();
    String b = idToken.getRawToken();
    return a != null && a.equals(b);
}

Try / catch

try {
    getName();
} catch (OIDCException e) {
    // force re-authentication / clear session
    redirectToAuthenticationEndpoint();
}

Prevention

When it happens

Trigger: GET / after code-flow authentication when SecurityIdentity.getIdToken().getToken() and the injected IdToken credential return different raw ID token strings — typically after a silent refresh or when an older cached token is injected.

Common situations: Quarkus OIDC versions with stale-token bugs in code-flow; multiple authentication mechanisms mixing tokens; refresh occurring between token acquisition points; incorrect quarkus.oidc token-path/refresh configuration.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/6312e85b81a60be2. Report an issue: GitHub.