quarkusio/quarkus · error · AuthenticationFailedException

Client certificate thumbprint does not match the token certi

Error message

Client certificate thumbprint does not match the token certificate thumbprint

What it means

Thrown when both the access token ('cnf.x5t#S256' claim) and the TLS connection have client certificate SHA-256 thumbprints, but they differ. This means the token was issued for (bound to) a different client certificate than the one presented on the current connection, so per RFC 8705 the token must be rejected.

Source

Thrown at extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcIdentityProvider.java:241

                if (resolvedContext.oidcConfig().token().binding().certificate()) {
                    result = result.onItem().transform(new Function<TokenVerificationResult, TokenVerificationResult>() {

                        @Override
                        public TokenVerificationResult apply(TokenVerificationResult t) {
                            String tokenCertificateThumbprint = getTokenCertThumbprint(requestData, t);
                            if (tokenCertificateThumbprint == null) {
                                LOG.warn(
                                        "Access token does not contain a confirmation 'cnf' claim with the certificate thumbprint");
                                throw new AuthenticationFailedException(tokenMap(request.getToken()));
                            }
                            String clientCertificateThumbprint = (String) requestData.get(OidcConstants.X509_SHA256_THUMBPRINT);
                            if (clientCertificateThumbprint == null) {
                                LOG.warn("Client certificate thumbprint is not available");
                                throw new AuthenticationFailedException(tokenMap(request.getToken()));
                            }
                            if (!clientCertificateThumbprint.equals(tokenCertificateThumbprint)) {
                                LOG.warn("Client certificate thumbprint does not match the token certificate thumbprint");
                                throw new AuthenticationFailedException(tokenMap(request.getToken()));
                            }
                            return t;
                        }

                    });
                }

                if (requestData.containsKey(OidcUtils.DPOP_PROOF_JWT_HEADERS)) {
                    result = result.onItem().transform(new Function<TokenVerificationResult, TokenVerificationResult>() {

                        @Override
                        public TokenVerificationResult apply(TokenVerificationResult t) {

                            String dpopJwkThumbprint = getDpopJwkThumbprint(requestData, t);
                            if (dpopJwkThumbprint == null) {
                                LOG.warn(
                                        "DPoP access token does not contain a confirmation 'cnf' claim with the JWK thumbprint");
                                throw new AuthenticationFailedException(invalidDPoPProofMap(request.getToken()));

View on GitHub (pinned to e1c734241f)

Solutions

  1. Obtain a fresh access token while authenticated with the same client certificate that is presented on the request.
  2. If certificates were rotated, clear the token cache and re-authenticate so a new 'cnf' thumbprint is minted.
  3. Verify the proxy/load balancer does not present its own certificate to Quarkus instead of the client's (use TLS passthrough).
  4. Confirm the certificate used matches by comparing its SHA-256 thumbprint with the token's cnf.x5t#S256 value offline.

Example fix

// before: reuse cached token after cert rotation
String token = cachedToken; // bound to old cert

// after: re-authenticate with current cert
OAuth2TokenSelector / OidcClient client = ...;
AccessToken token = client.authenticate(certCredential); // new cert -> new cnf claim
Defensive patterns

Strategy: try-catch

Try / catch

try {
    return callProtectedApi(token);
} catch (AuthenticationFailedException e) {
    // cert thumbprint mismatch: refresh token with the current cert
    return callProtectedApi(reauthenticateWithCurrentCert());
}

Prevention

When it happens

Trigger: A client presents certificate A on TLS but uses an access token bound to certificate B — e.g. reusing a token obtained with a different keystore entry, rotating client certificates without re-obtaining tokens, or load-balancing requests to a backend with mismatched certs.

Common situations: Certificate rotation: server keystore updated but cached tokens still bound to the old cert. Multiple services behind one identity sharing tokens. Copying tokens between environments (dev vs prod keystores).

Understand the failure class

Related errors


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