{"record":{"id":"d62672329da9392f","repo":"quarkusio/quarkus","slug":"dpop-proof-jwk-header-does-not-represent-a-valid-j","errorCode":null,"errorMessage":"DPoP proof jwk header does not represent a valid JWK key","messagePattern":"DPoP proof jwk header does not represent a valid JWK key","errorType":"exception","errorClass":"AuthenticationFailedException","httpStatus":401,"severity":"error","filePath":"extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcIdentityProvider.java","lineNumber":275,"sourceCode":"                                LOG.warn(\n                                        \"DPoP access token does not contain a confirmation 'cnf' claim with the JWK thumbprint\");\n                                throw new AuthenticationFailedException(invalidDPoPProofMap(request.getToken()));\n                            }\n\n                            JsonObject proofHeaders = (JsonObject) requestData.get(OidcUtils.DPOP_PROOF_JWT_HEADERS);\n\n                            JsonObject jwkProof = proofHeaders.getJsonObject(OidcConstants.DPOP_JWK_HEADER);\n                            if (jwkProof == null) {\n                                LOG.warn(\"DPoP proof jwk header is missing\");\n                                throw new AuthenticationFailedException(invalidDPoPProofMap(request.getToken()));\n                            }\n\n                            PublicJsonWebKey publicJsonWebKey = null;\n                            try {\n                                publicJsonWebKey = PublicJsonWebKey.Factory.newPublicJwk(jwkProof.getMap());\n                            } catch (JoseException ex) {\n                                LOG.warn(\"DPoP proof jwk header does not represent a valid JWK key\");\n                                throw new AuthenticationFailedException(ex, invalidDPoPProofMap(request.getToken()));\n                            }\n\n                            if (publicJsonWebKey.getPrivateKey() != null) {\n                                LOG.warn(\"DPoP proof JWK key is a private key but it must be a public key\");\n                                throw new AuthenticationFailedException(invalidDPoPProofMap(request.getToken()));\n                            }\n\n                            byte[] jwkProofDigest = publicJsonWebKey.calculateThumbprint(\"SHA-256\");\n                            String jwkProofThumbprint = OidcCommonUtils.base64UrlEncode(jwkProofDigest);\n\n                            if (!dpopJwkThumbprint.equals(jwkProofThumbprint)) {\n                                LOG.warn(\"DPoP access token JWK thumbprint does not match the DPoP proof JWK thumbprint\");\n                                throw new AuthenticationFailedException(invalidDPoPProofMap(request.getToken()));\n                            }\n\n                            try {\n                                JsonWebSignature jws = new JsonWebSignature();\n                                jws.setAlgorithmConstraints(OidcProvider.ASYMMETRIC_ALGORITHM_CONSTRAINTS);","sourceCodeStart":257,"sourceCodeEnd":293,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcIdentityProvider.java#L257-L293","documentation":"Thrown when the DPoP proof's 'jwk' header is present but its contents cannot be parsed as a valid public JWK by jose4j (PublicJsonWebKey.Factory.newPublicJwk throws JoseException). The proof's key material is malformed or of an unsupported type, so verification cannot proceed.","triggerScenarios":"The jwk header map has missing/incorrect members (wrong 'kty', missing 'crv' for EC, bad base64url 'n'/'e' for RSA), or the JSON is not a JWK at all (e.g. a PEM string or certificate object pasted in).","commonSituations":"Manually serializing a java.security.PublicKey incorrectly; using an unsupported curve/algorithm; double-encoding the JWK as a JSON string instead of an object inside the header.","solutions":["Emit a standards-compliant JWK object in the header: kty, and for EC kty=EC with crv/x/y, for RSA kty=RSA with n/e, base64url-encoded without padding.","Use an established JOSE library (jose4j, nimbus-jose-jwt) to build the proof instead of hand-rolling the header.","Avoid unsupported key types/curves; prefer ES256 (P-256) which Quarkus and ASes widely support.","Validate locally with PublicJsonWebKey.Factory.newPublicJwk(json) before sending the proof."],"exampleFix":"// before: PEM string in header\n\"jwk\": \"-----BEGIN PUBLIC KEY-----...\"\n\n// after: proper JWK object\n\"jwk\": {\"kty\":\"EC\",\"crv\":\"P-256\",\"x\":\"...\",\"y\":\"...\"}","handlingStrategy":"validation","validationCode":"// Pre-validate the JWK with jose4j before sending the proof\ntry {\n    PublicJsonWebKey.Factory.newPublicJwk(jwkMap);\n} catch (JoseException e) {\n    throw new IllegalArgumentException(\"Proof jwk header is not a valid public JWK\", e);\n}","typeGuard":"static boolean isValidPublicJwk(Map<String,Object> jwk) {\n    try { PublicJsonWebKey.Factory.newPublicJwk(jwk); return true; }\n    catch (JoseException e) { return false; }\n}","tryCatchPattern":"try {\n    return callWithProof(buildProof());\n} catch (AuthenticationFailedException e) {\n    throw new IllegalStateException(\"Fix proof jwk: use kty EC (crv/x/y) or RSA (n/e), base64url\", e);\n}","preventionTips":["Prefer ES256/P-256 keys — universally supported","Emit only standard JWK members, base64url without padding","Never place a PEM or certificate string in the jwk header","Round-trip test: serialize, parse, verify locally before deploying"],"tags":["oidc","dpop","jwk","invalid-key"],"backgroundTag":"dpop-invalid-jwk","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}