quarkusio/quarkus · error · AuthenticationFailedException
DPoP proof token signature is invalid
Error message
DPoP proof token signature is invalid
What it means
Thrown when the DPoP proof JWT's signature fails verification (jose4j's JsonWebSignature.verifySignature() returns false) against the public key from the proof's own jwk header. The proof payload or header was modified after signing, or it was signed with a different key than the one declared in the header.
Source
Thrown at extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcIdentityProvider.java:298
throw new AuthenticationFailedException(invalidDPoPProofMap(request.getToken()));
}
byte[] jwkProofDigest = publicJsonWebKey.calculateThumbprint("SHA-256");
String jwkProofThumbprint = OidcCommonUtils.base64UrlEncode(jwkProofDigest);
if (!dpopJwkThumbprint.equals(jwkProofThumbprint)) {
LOG.warn("DPoP access token JWK thumbprint does not match the DPoP proof JWK thumbprint");
throw new AuthenticationFailedException(invalidDPoPProofMap(request.getToken()));
}
try {
JsonWebSignature jws = new JsonWebSignature();
jws.setAlgorithmConstraints(OidcProvider.ASYMMETRIC_ALGORITHM_CONSTRAINTS);
jws.setCompactSerialization((String) requestData.get(OidcUtils.DPOP_PROOF));
jws.setKey(publicJsonWebKey.getPublicKey());
if (!jws.verifySignature()) {
LOG.warn("DPoP proof token signature is invalid");
throw new AuthenticationFailedException(invalidDPoPProofMap(request.getToken()));
}
} catch (JoseException ex) {
LOG.warn("DPoP proof token signature can not be verified");
throw new AuthenticationFailedException(ex, invalidDPoPProofMap(request.getToken()));
}
JsonObject proofClaims = (JsonObject) requestData.get(OidcUtils.DPOP_PROOF_JWT_CLAIMS);
// Calculate the access token thumprint and compare with the `ath` claim
String accessTokenProof = proofClaims.getString(OidcConstants.DPOP_ACCESS_TOKEN_THUMBPRINT);
if (accessTokenProof == null) {
LOG.warn("DPoP proof access token hash is missing");
throw new AuthenticationFailedException(invalidDPoPProofMap(request.getToken()));
}
String accessTokenHash = null;
try {View on GitHub (pinned to e1c734241f)
Solutions
- Fix the proof generator to compute the compact JWS only after all header and claim values are final.
- Verify the jwk header key is exactly the key used to sign the proof.
- Avoid proxies/interceptors that modify the DPoP header or its inputs after signing.
- Catch AuthenticationFailedException, regenerate the proof, and retry once with a freshly signed JWT.
Example fix
// before: mutate claims after signing
jws.setPayload(claims); jws.sign();
claims.put("iat", now); // invalidates signature
// after: finalize claims, then sign
claims.put("iat", now);
jws.setPayload(claims);
jws.sign(); Defensive patterns
Strategy: try-catch
Validate before calling
// Verify the proof signature locally before sending
JsonWebSignature jws = new JsonWebSignature();
jws.setCompactSerialization(proof);
jws.setKey(publicKey);
if (!jws.verifySignature()) throw new IllegalStateException("Proof was not signed with the jwk header key"); Try / catch
try {
return callWithProof();
} catch (AuthenticationFailedException e) {
return callWithProofWithFreshlySignedJwt(); // rebuild proof, sign last
} Prevention
- Sign only after all header and claim values are final
- Ensure the jwk header key is the exact signing key
- Keep proxies/interceptors from mutating the DPoP header
- Generate a new proof per request with fresh iat/jti
When it happens
Trigger: A middleman or buggy client rewrites proof claims (iat, htu, nonce) after signing; the client signs with one key but embeds another in the jwk header; corrupted encoding of the compact serialization.
Common situations: Proxies that re-sign or re-serialize the DPoP header; home-grown proof builders that serialize claims after signing; clock-adjustment code that mutates the iat claim post-signature.
Related errors
- DPoP proof token signature can not be verified
- %s type can not be used to represent JWT claims in @Singleto
- DPoP access token does not contain a confirmation 'cnf' clai
- DPoP proof jwk header is missing
- DPoP proof jwk header does not represent a valid JWK key
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/f2573d4748db0559.
Report an issue: GitHub.