{"record":{"id":"6a8b8c87eaf9be83","repo":"jwtk/jjwt","slug":"jwt-signature-does-not-match-locally-computed-sign","errorCode":null,"errorMessage":"JWT signature does not match locally computed signature. JWT validity cannot be asserted and should not be trusted.","messagePattern":"JWT signature does not match locally computed signature\\. JWT validity cannot be asserted and should not be trusted\\.","errorType":"exception","errorClass":"SignatureException","httpStatus":null,"severity":"error","filePath":"impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java","lineNumber":341,"sourceCode":"            buf.put(headerBuf);\n            buf.put((byte) SEPARATOR_CHAR);\n            buf.rewind();\n            byte[] data = new byte[buf.remaining()];\n            buf.get(data);\n            InputStream prefixStream = Streams.of(data);\n            payloadStream = payload.toInputStream();\n            // We wrap the payloadStream here in an UncloseableInputStream to prevent the SequenceInputStream from\n            // closing it since we'll need to rewind/reset it if decompression is enabled\n            verificationInput = new SequenceInputStream(prefixStream, new UncloseableInputStream(payloadStream));\n        }\n\n        try {\n            VerifySecureDigestRequest<Key> request =\n                    new DefaultVerifySecureDigestRequest<>(verificationInput, provider, null, key, signature);\n            if (!algorithm.verify(request)) {\n                String msg = \"JWT signature does not match locally computed signature. JWT validity cannot be \" +\n                        \"asserted and should not be trusted.\";\n                throw new SignatureException(msg);\n            }\n        } catch (WeakKeyException e) {\n            throw e;\n        } catch (InvalidKeyException | IllegalArgumentException e) {\n            String algId = algorithm.getId();\n            String msg = \"The parsed JWT indicates it was signed with the '\" + algId + \"' signature \" +\n                    \"algorithm, but the provided \" + key.getClass().getName() + \" key may \" +\n                    \"not be used to verify \" + algId + \" signatures.  Because the specified \" +\n                    \"key reflects a specific and expected algorithm, and the JWT does not reflect \" +\n                    \"this algorithm, it is likely that the JWT was not expected and therefore should not be \" +\n                    \"trusted.  Another possibility is that the parser was provided the incorrect \" +\n                    \"signature verification key, but this cannot be assumed for security reasons.\";\n            throw new UnsupportedJwtException(msg, e);\n        } finally {\n            Streams.reset(payloadStream);\n        }\n\n        return signature;","sourceCodeStart":323,"sourceCodeEnd":359,"githubUrl":"https://github.com/jwtk/jjwt/blob/fb71496164c71442d08adec4571d9616ed5e1b8d/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java#L323-L359","documentation":"The signature bytes decoded from the compact JWT do not match the signature the parser computes locally over the header+payload with the resolved key and algorithm. algorithm.verify(request) returned false, so the token is untrusted and a SignatureException is thrown.","triggerScenarios":"Parsing a JWS signed with a different key than the verification key; token payload/header tampered with in transit; token copied with corrupted characters (e.g. trailing whitespace/newline, truncated string).","commonSituations":"Environment mismatch (token signed in dev with dev key, verified in prod); key rotation without JWKS refresh; manually editing a JWT's claims; storing tokens through channels that mangle Base64Url (URL-encoding, line wrapping).","solutions":["Verify you are using the exact key the token was signed with (same secret, or matching public key)","Re-obtain the token from a trusted issuer and confirm it was not altered in transit or storage","Confirm the token string is complete and unmodified (no truncation, whitespace, or encoding transformations)"],"exampleFix":"// before\nJws<Claims> jws = Jwts.parser().verifyWith(oldKey).build().parseSignedClaims(token);\n// after\nSecretKey currentKey = keyStore.currentSigningKey(); // key matching the issuer's\nJws<Claims> jws = Jwts.parser().verifyWith(currentKey).build().parseSignedClaims(token);","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    return Jwts.parser().verifyWith(key).build().parseSignedClaims(token);\n} catch (SignatureException e) {\n    if (e.getMessage().contains(\"does not match locally computed signature\")) {\n        throw new UnauthorizedException(\"Invalid token signature\", e);\n    }\n    throw e;\n}","preventionTips":["Keep signing and verification keys synchronized across environments","Handle key rotation with a key set keyed by kid","Avoid transporting tokens through channels that alter the string (encoding, wrapping)"],"tags":["jwt","signature-mismatch","security"],"backgroundTag":"jwt-signature-verification-failed","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"}