quarkusio/quarkus · error · AuthenticationFailedException
DPoP proof jwk header is missing
Error message
DPoP proof jwk header is missing
What it means
Thrown when the DPoP proof JWT's 'jwk' JOSE header — required by RFC 9449 to carry the public key used to sign the proof — is missing. Without it Quarkus cannot know which key must verify the proof signature, so authentication fails.
Source
Thrown at extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcIdentityProvider.java:267
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()));
}
JsonObject proofHeaders = (JsonObject) requestData.get(OidcUtils.DPOP_PROOF_JWT_HEADERS);
JsonObject jwkProof = proofHeaders.getJsonObject(OidcConstants.DPOP_JWK_HEADER);
if (jwkProof == null) {
LOG.warn("DPoP proof jwk header is missing");
throw new AuthenticationFailedException(invalidDPoPProofMap(request.getToken()));
}
PublicJsonWebKey publicJsonWebKey = null;
try {
publicJsonWebKey = PublicJsonWebKey.Factory.newPublicJwk(jwkProof.getMap());
} catch (JoseException ex) {
LOG.warn("DPoP proof jwk header does not represent a valid JWK key");
throw new AuthenticationFailedException(ex, invalidDPoPProofMap(request.getToken()));
}
if (publicJsonWebKey.getPrivateKey() != null) {
LOG.warn("DPoP proof JWK key is a private key but it must be a public key");
throw new AuthenticationFailedException(invalidDPoPProofMap(request.getToken()));
}
byte[] jwkProofDigest = publicJsonWebKey.calculateThumbprint("SHA-256");
String jwkProofThumbprint = OidcCommonUtils.base64UrlEncode(jwkProofDigest);
View on GitHub (pinned to e1c734241f)
Solutions
- Regenerate the DPoP proof ensuring the JOSE header contains {typ:'dpop+jwt', alg:'ES256', jwk:<public key JWK>}.
- Upgrade or correctly configure the DPoP library so it embeds the public JWK in the proof header.
- Verify the proof is a 3-part compact JWS (header.payload.signature) and the header parses as JSON with a jwk object.
- Catch AuthenticationFailedException, log the proof header (without secrets), and fix the proof generator.
Example fix
// before
Map<String,Object> header = Map.of("typ","dpop+jwt","alg","ES256");
// after
Map<String,Object> header = Map.of(
"typ","dpop+jwt",
"alg","ES256",
"jwk", publicKeyJwk.toJson()); // RFC 9449 requires embedded public JWK Defensive patterns
Strategy: validation
Validate before calling
// Validate the proof header locally before sending
JsonObject header = decodeJoseHeader(proof);
if (header.getJsonObject("jwk") == null) {
throw new IllegalArgumentException("DPoP proof must embed the public JWK in its jwk header");
} Type guard
static boolean proofHasJwkHeader(String compactJws) {
String[] parts = compactJws.split("\\.");
if (parts.length != 3) return false;
var h = Json.decodeValue(Base64.getUrlDecoder().decode(parts[0]));
return h instanceof JsonObject jo && jo.containsKey("jwk");
} Prevention
- Use a JOSE library to build proofs; never hand-roll the header
- Header must contain typ=dpop+jwt, alg, and jwk
- Unit-test proof generation against PublicJsonWebKey.Factory parsing
- Log (redacted) proof headers when debugging DPoP 401s
When it happens
Trigger: The DPoP proof header value sent by the client is a JWT whose header lacks the 'jwk' member: hand-built proofs, proofs generated by a library with a non-standard configuration, or the 'DPoP' header containing something other than a complete proof JWT.
Common situations: Manually constructing the DPoP proof JSON and forgetting the jwk header; using an HTTP client interceptor that signs with 'typ':dpop+jwt but omits embedded jwk; forwarding only claims instead of the full JWT.
Related errors
- DPoP proof access token hash is missing
- DPoP access token does not contain a confirmation 'cnf' clai
- DPoP proof jwk header does not represent a valid JWK key
- DPoP proof JWK key is a private key but it must be a public
- DPoP access token JWK thumbprint does not match the DPoP pro
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/c24d90bc68608d11.
Report an issue: GitHub.