quarkusio/quarkus · error · AuthenticationFailedException

Access token does not contain a confirmation 'cnf' claim wit

Error message

Access token does not contain a confirmation 'cnf' claim with the certificate thumbprint

What it means

During mTLS token-binding verification (OAuth2 certificate-bound tokens / RFC 8705), OidcIdentityProvider checks the verified access token for a 'cnf' claim containing the x5t#S256 certificate thumbprint. If getTokenCertThumbprint() returns null the token is not certificate-bound, a warning is logged and AuthenticationFailedException is thrown.

Source

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

            } else {
                return verifySelfSignedTokenUni(resolvedContext, request.getToken().getToken());
            }
        } else {
            final boolean idToken = isIdToken(request);
            final TokenType tokenType = idToken ? TokenType.ID_TOKEN : TokenType.BEARER_ACCESS_TOKEN;
            Uni<TokenVerificationResult> result = verifyTokenUni(requestData, resolvedContext, request.getToken(), tokenType,
                    idToken, userInfo);
            if (!idToken) {
                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>() {

View on GitHub (pinned to e1c734241f)

Solutions

  1. Configure your Authorization Server to issue certificate-bound access tokens (mtls 'cnf' claim, RFC 8705) for mTLS client-authenticated clients.
  2. If binding is not required, set quarkus.oidc.token.binding (token-binding) to 'none' so the thumbprint check is skipped.
  3. Verify end-to-end mTLS (no TLS offloading losing the client certificate) so the IdP can include the certificate thumbprint in the token.

Example fix

// before (application.properties)
quarkus.oidc.token.binding=verify
// IdP issues tokens without cnf => AuthenticationFailedException

// after - either fix IdP to bind tokens, or disable verification
quarkus.oidc.token.binding=none
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-flight: confirm IdP issues bound tokens before enabling verification
// Decode the access token payload and check the cnf claim
boolean certificateBound = jwtClaims.contains("cnf")
    && jwtClaims.getJsonObject("cnf").containsKey("x5t#S256");
if (!certificateBound && bindingRequired) { warn("IdP does not bind tokens to certificates"); }

Type guard

boolean hasCnfThumbprint(jakarta.json.JsonObject claims) {
    return claims.containsKey("cnf")
        && claims.getJsonObject("cnf").containsKey("x5t#S256");
}

Try / catch

try {
    identity = identityProvider.authenticate(event, identityManager);
} catch (AuthenticationFailedException e) {
    if (e.getMessage() != null && e.getMessage().contains("cnf")) {
        // token not certificate-bound: review quarkus.oidc.token.binding or IdP config
    }
    throw e;
}

Prevention

When it happens

Trigger: quarkus.oidc.token.binding=verify (certificate-bound tokens required) but the IdP-issued access token lacks a cnf/x5t#S256 claim - e.g. the Authorization Server does not bind tokens to the client certificate, or the access token was issued without mTLS key confirmation.

Common situations: Enabling token binding verification while the OAuth2 provider never issues cnf claims; tokens minted by a different issuer or flow without client-certificate binding; proxies terminating TLS so the certificate thumbprint never reaches the IdP.

Understand the failure class

Related errors


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