{"record":{"id":"616d34cbb1e28585","repo":"jwtk/jjwt","slug":"unable-to-verify-jws-signature-the-parser-has-enc","errorCode":null,"errorMessage":"Unable to verify JWS signature: the parser has encountered an Unencoded Payload JWS with detached payload, but the detached payload value required for signature verification has not been provided. If you expect to receive and parse Unencoded Payload JWSs in your application, the overloaded JwtParser.parseSignedContent or JwtParser.parseSignedClaims methods that accept a byte[] or InputStream must be used for these kinds of JWSs. Header: %s","messagePattern":"Unable to verify JWS signature: the parser has encountered an Unencoded Payload JWS with detached payload, but the detached payload value required for signature verification has not been provided\\. If you expect to receive and parse Unencoded Payload JWSs in your application, the overloaded JwtParser\\.parseSignedContent or JwtParser\\.parseSignedClaims methods that accept a byte\\[\\] or InputStream must be used for these kinds of JWSs\\. Header: (.+?)","errorType":"exception","errorClass":"SignatureException","httpStatus":null,"severity":"error","filePath":"impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java","lineNumber":477,"sourceCode":"        // check if b64 extension enabled:\n        final boolean payloadBase64UrlEncoded = !(header instanceof JwsHeader) || ((JwsHeader) header).isPayloadEncoded();\n        if (payloadBase64UrlEncoded) {\n            // standard encoding, so decode it:\n            byte[] data = decode(payloadToken, \"payload\");\n            payload = new Payload(data, header.getContentType());\n        } else {\n            // The JWT uses the b64 extension, and we already know the parser supports that extension at this point\n            // in the code execution path because of the ----- crit ----- assertions section above as well as the\n            // (JwsHeader).isPayloadEncoded() check\n            if (Strings.hasText(payloadToken)) {\n                // we need to verify what was in the token, otherwise it'd be a security issue if we ignored it\n                // and assumed the (likely safe) unencodedPayload value instead:\n                payload = new Payload(payloadToken, header.getContentType());\n            } else {\n                //no payload token (a detached payload), so we need to ensure that they've specified the payload value:\n                if (unencodedPayload.isEmpty()) {\n                    String msg = String.format(B64_MISSING_PAYLOAD, header);\n                    throw new SignatureException(msg);\n                }\n                // otherwise, use the specified payload:\n                payload = unencodedPayload;\n            }\n        }\n\n        if (tokenized instanceof TokenizedJwe && payload.isEmpty()) {\n            // Only JWS payload can be empty per https://github.com/jwtk/jjwt/pull/540\n            String msg = \"Compact JWE strings MUST always contain a payload (ciphertext).\";\n            throw new MalformedJwtException(msg);\n        }\n\n        byte[] iv = null;\n        byte[] digest = null; // either JWE AEAD tag or JWS signature after Base64Url-decoding\n        if (tokenized instanceof TokenizedJwe) {\n\n            TokenizedJwe tokenizedJwe = (TokenizedJwe) tokenized;\n            JweHeader jweHeader = Assert.stateIsInstance(JweHeader.class, header, \"Not a JweHeader. \");","sourceCodeStart":459,"sourceCodeEnd":495,"githubUrl":"https://github.com/jwtk/jjwt/blob/fb71496164c71442d08adec4571d9616ed5e1b8d/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java#L459-L495","documentation":"For Unencoded Payload JWSs (b64=false, 'b64' critical) with a detached payload, the compact string contains no payload segment, so the caller must supply the raw payload bytes for signature verification. When unencodedPayload is empty during parse, jjwt throws SignatureException instructing the caller to use the parseSignedContent(byte[]) / parseSignedClaims(byte[]) overloads.","triggerScenarios":"Calling parse() (no payload argument) on a JWS with header {\"b64\":false,\"crit\":[\"b64\"]} and an empty payload segment; or calling an overload passing null/empty byte[] for the detached payload.","commonSituations":"Detached-payload flows (e.g. OAuth DPoP-like or large-payload signing) where the application received the JWS but the payload separately and forgot to pass it; calling plain parse() out of habit instead of parseSignedContent(payload).","solutions":["Use the detached-payload overloads: parser.parseSignedContent(detachedPayloadBytes) or parseSignedClaims(detachedPayloadBytes).","Ensure the exact raw (unencoded) payload bytes that were signed are supplied — any difference fails verification.","If you don't actually use unencoded payloads, have the issuer stop setting b64:false/crit:[\"b64\"].","Check ordering bugs where the payload is fetched asynchronously but parse is called before it arrives."],"exampleFix":"// before\nJws<Claims> jws = Jwts.parser().verifyWith(key)\n    .critical().add(\"b64\").and().build().parse(token);\n\n// after: supply the detached payload\nbyte[] payload = ...; // exact raw payload that was signed\nJws<Claims> jws = Jwts.parser().verifyWith(key)\n    .critical().add(\"b64\").and().build()\n    .parseSignedClaims(payload, token);","handlingStrategy":"validation","validationCode":"if (headerB64FalseDetachedPayload && (unencodedPayload == null || unencodedPayload.length == 0)) throw new IllegalStateException(\"detached payload bytes required: use parseSignedContent(payload, token)\");","typeGuard":null,"tryCatchPattern":"try { return parser.parseSignedContent(detachedPayload, token); }\ncatch (io.jsonwebtoken.SignatureException e) { throw new InvalidTokenException(\"missing detached payload for unencoded-payload JWS\", e); }","preventionTips":["Always use parseSignedContent/parseSignedClaims overloads that take the payload when tokens may be detached","Pass the exact raw bytes that were signed; don't re-encode them","Ensure the payload is fetched before invoking the parser","Reserve plain parse() for standard (non-detached) tokens"],"tags":["jwt","jws","detached-payload","unencoded-payload","signature"],"backgroundTag":"missing-required-argument","analyzedSha":"fb71496164c71442d08adec4571d9616ed5e1b8d","analyzedAt":"2026-09-09T00:33:09.982Z","contentChangedAt":"2026-09-09T00:33:09.982Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}