quarkusio/quarkus · error · AuthenticationFailedException
Client certificate thumbprint is not available
Error message
Client certificate thumbprint is not available
What it means
This AuthenticationFailedException is thrown by Quarkus OIDC's OidcIdentityProvider when verifying an access token bound to an mTLS client certificate (RFC 8705). The token carries a 'cnf' claim with an 'x5t#S256' certificate thumbprint, but the certificate presented on the current TLS connection has no thumbprint available, so binding cannot be verified. The provider fails authentication rather than trusting an unverifiable certificate-bound token.
Source
Thrown at extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcIdentityProvider.java:237
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>() {
@Override
public TokenVerificationResult apply(TokenVerificationResult t) {
String dpopJwkThumbprint = getDpopJwkThumbprint(requestData, t);View on GitHub (pinned to e1c734241f)
Solutions
- Enable client certificate authentication so the thumbprint is populated: set quarkus.http.auth.certificate-role-attributes / ensure quarkus.http.ssl.client-auth=REQUIRED (or REQUEST) on the listener serving OIDC.
- If terminating TLS at a proxy, forward the client certificate and configure the recorder that populates X509_SHA256_THUMBPRINT (e.g. via a custom Vert.x peer certificate extraction or proxy header handling).
- Ensure the token issuer issues mTLS-bound tokens only for callers that actually present certificates; otherwise request a non-certificate-bound token.
- Catch AuthenticationFailedException in a custom authentication exception mapper and return 401 with guidance about presenting the client certificate.
Example fix
// before (proxy terminates TLS, Quarkus sees no cert) # application.properties quarkus.http.ssl.client-auth=NONE // after quarkus.http.ssl.client-auth=REQUIRED # and at the proxy: pass through the client cert (e.g. PROXY protocol v2 with cert extension, or re-encrypt TLS)
Defensive patterns
Strategy: validation
Validate before calling
// Before calling the API, ensure mTLS is active and a cert thumbprint is present
if (sslSession.getPeerCertificates().length == 0) {
throw new IllegalStateException("mTLS-bound token used without a client certificate");
}
// Optionally compare with token cnf.x5t#S256 yourself Type guard
static boolean hasClientCert(SecurityContext ctx) {
return ctx != null && ctx.getUserPrincipal() instanceof CertificatePrincipal;
} Prevention
- Set quarkus.http.ssl.client-auth=REQUIRED for endpoints consuming cert-bound tokens
- Use TLS passthrough at proxies instead of termination, or forward client certs
- Only request cert-bound tokens (RFC 8705) from ASes when you always present the cert
- Smoke-test over the real TLS topology, not just localhost
When it happens
Trigger: An access token whose 'cnf' claim contains an 'x5t#S256' thumbprint arrives on a request whose client certificate was not captured into OidcConstants.X509_SHA256_THUMBPRINT request data (e.g. mutual TLS not enabled on the HTTP listener, or the CertificateAuthRequestDataRecorder/vert.x peer certificate is absent because TLS terminates at a proxy).
Common situations: TLS offloaded at a load balancer or reverse proxy so Quarkus never sees the client certificate; quarkus.http.ssl.certificate files configured without client-auth=REQUIRED; testing over plain HTTP with an mTLS-bound token from a different environment.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- Client certificate thumbprint does not match the token certi
- The '%s' annotation is only supported when proactive authent
- Access token does not contain a confirmation 'cnf' claim wit
- DPoP access token does not contain a confirmation 'cnf' clai
- DPoP access token hash does not match the DPoP proof access
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/9e03bb3f2b14413d.
Report an issue: GitHub.