JWT Signature Invalid — Causes and How to Fix
💡A JWT signature invalid error means the token cannot be verified with the provided secret or key. The most common causes are a wrong or differently-encoded secret, an algorithm mismatch between signing and verification, or a modified token payload. Inspect the JWT header to confirm the algorithm, then verify the secret encoding matches.
Quick Diagnosis
If you see “JsonWebTokenError: invalid signature” → it means the secret or public key used to verify does not match the one used to sign → do this: confirm the signing secret matches the verification secret exactly, including encoding
If you see “algorithm mismatch” → it means the token was signed with HS256 but verified with RS256 (or vice versa) → do this: read the alg field in the JWT header and use the same algorithm for verification
If you see “signature valid in jwt.io but invalid in code” → it means the secret is encoded differently (raw string vs Base64 vs hex) → do this: decode the secret to its raw bytes before using it for verification
If you see “token was modified after signing” → it means payload or header was altered — the signature no longer matches → do this: do not modify JWT payload after signing — re-sign with the correct payload instead
Inspect Your JWT Token
Decode your JWT and inspect the header, payload, and signature fields to confirm the algorithm and claims before debugging verification code.
Common Causes and Fixes
Wrong secret encoding
❌ Wrong
// Secret stored as Base64 but used as plain string
const secret = "c2VjcmV0";
jwt.verify(token, secret);
// → invalid signature✅ Fixed
// Decode Base64 secret to raw bytes first
const secret = Buffer.from("c2VjcmV0", "base64");
jwt.verify(token, secret);
// → validIf the signing service encodes the secret in Base64, you must decode it to raw bytes before verifying.
Algorithm mismatch (HS256 vs RS256)
❌ Wrong
// Token signed with RS256 private key
// Verified with shared string (HS256 mode)
jwt.verify(token, "sharedsecret");
// → invalid signature✅ Fixed
// Verify with the RS256 public key
const publicKey = fs.readFileSync("public.pem");
jwt.verify(token, publicKey, { algorithms: ["RS256"] });
// → validRS256 tokens require a PEM public key for verification, not a shared secret string.
Debugging Checklist
- ✓Decode the JWT header and confirm the alg field (HS256, RS256, ES256, etc.)
- ✓Use the same algorithm for verification as was used for signing
- ✓Confirm the secret encoding matches — raw string, Base64-decoded bytes, or PEM key
- ✓Do not modify the JWT payload or header after signing
- ✓For RS256/ES256, verify with the public key, not the private key
- ✓Check that the token has not expired (exp claim) before debugging the signature
Related Guides
Frequently Asked Questions
What does JWT signature invalid mean?
It means the token's signature cannot be verified with the provided secret or key. The token may have been signed with a different secret, a different algorithm, or modified after signing.
Can I fix an invalid JWT signature?
No. A signature cannot be repaired — you must re-issue a correctly signed token. The signature exists precisely to detect tampering.
Why does my JWT verify in jwt.io but not in my code?
jwt.io uses the raw secret string. If your code receives the secret as Base64 or hex, you must decode it to raw bytes before verifying.
All tools run in your browser. Your data never leaves your device.