{"record":{"id":"601de83fba7428ac","repo":"quarkusio/quarkus","slug":"dpop-proof-token-signature-can-not-be-verified","errorCode":null,"errorMessage":"DPoP proof token signature can not be verified","messagePattern":"DPoP proof token signature can not be verified","errorType":"exception","errorClass":"AuthenticationFailedException","httpStatus":401,"severity":"error","filePath":"extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcIdentityProvider.java","lineNumber":302,"sourceCode":"                            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);\n                                jws.setCompactSerialization((String) requestData.get(OidcUtils.DPOP_PROOF));\n                                jws.setKey(publicJsonWebKey.getPublicKey());\n                                if (!jws.verifySignature()) {\n                                    LOG.warn(\"DPoP proof token signature is invalid\");\n                                    throw new AuthenticationFailedException(invalidDPoPProofMap(request.getToken()));\n                                }\n                            } catch (JoseException ex) {\n                                LOG.warn(\"DPoP proof token signature can not be verified\");\n                                throw new AuthenticationFailedException(ex, invalidDPoPProofMap(request.getToken()));\n                            }\n\n                            JsonObject proofClaims = (JsonObject) requestData.get(OidcUtils.DPOP_PROOF_JWT_CLAIMS);\n\n                            // Calculate the access token thumprint and compare with the `ath` claim\n\n                            String accessTokenProof = proofClaims.getString(OidcConstants.DPOP_ACCESS_TOKEN_THUMBPRINT);\n                            if (accessTokenProof == null) {\n                                LOG.warn(\"DPoP proof access token hash is missing\");\n                                throw new AuthenticationFailedException(invalidDPoPProofMap(request.getToken()));\n                            }\n\n                            String accessTokenHash = null;\n                            try {\n                                accessTokenHash = OidcCommonUtils.base64UrlEncode(\n                                        OidcUtils.getSha256Digest(request.getToken().getToken()));\n                            } catch (NoSuchAlgorithmException ex) {\n                                // SHA256 is always supported","sourceCodeStart":284,"sourceCodeEnd":320,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcIdentityProvider.java#L284-L320","documentation":"Thrown when verifying the DPoP proof throws a JoseException (malformed compact serialization, unsupported algorithm, key/alg conflict, etc.), so the signature cannot even be attempted/verified. Unlike error 1227 (verification returned false), this is an exception during the verification process itself.","triggerScenarios":"The DPoP proof string is not a valid 3-segment compact JWS; the proof's 'alg' is not an asymmetric algorithm accepted by OidcProvider.ASYMMETRIC_ALGORITHM_CONSTRAINTS (e.g. HS256, or 'none'); corrupt base64url segments.","commonSituations":"Sending a JWE or opaque token in the DPoP header; clients using symmetric algorithms; truncation of the header value by middleware or size-limited HTTP stacks.","solutions":["Sign the proof with an asymmetric algorithm allowed by the constraints (ES256/RS256 etc.) and send the standard compact JWS.","Check that no intermediary truncates or re-encodes the DPoP header value.","Locally pre-verify with jose4j (new JsonWebSignature + verifySignature) before sending to catch malformed proofs early.","Catch AuthenticationFailedException, log the JoseException cause, and fix the proof construction accordingly."],"exampleFix":"// before\njws.setAlgorithmConstraints(...); jws.setKey(hmacKey); // symmetric -> rejected\n\n// after\njws.setAlgorithmConstraints(ASYMMETRIC_ALGORITHM_CONSTRAINTS);\njws.setKey(ecPublicKey); // ES256 and similar asymmetric algs only","handlingStrategy":"validation","validationCode":"// Pre-parse and constrain algorithms before sending\ntry {\n    JsonWebSignature jws = new JsonWebSignature();\n    jws.setCompactSerialization(proof);\n    jws.setAlgorithmConstraints(OidcProvider.ASYMMETRIC_ALGORITHM_CONSTRAINTS);\n    jws.setKey(publicKey);\n    jws.verifySignature();\n} catch (JoseException e) {\n    throw new IllegalArgumentException(\"Malformed proof or unsupported/symmetric alg\", e);\n}","typeGuard":"static boolean isCompactJws(String s) {\n    return s != null && s.chars().filter(c -> c == '.').count() == 2 && !s.contains(\" \");\n}","tryCatchPattern":"try {\n    return call();\n} catch (AuthenticationFailedException e) {\n    log.warnf(\"DPoP proof rejected (JoseException cause): check alg/key and compact form\");\n    return callWithRebuiltProof();\n}","preventionTips":["Use asymmetric algorithms only (ES256, RS256, EdDSA); never HS256 or none","Send a standard 3-segment compact JWS in the DPoP header","Check intermediaries for header truncation/re-encoding","Pre-verify with jose4j locally in tests"],"tags":["oidc","dpop","jose-exception","signature-verification"],"backgroundTag":"dpop-proof-verification-error","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"}