JWT Invalid Signature Errors — Causes and Fixes
Invalid signature errors mean your JWT cannot be verified. This guide covers every cause and the exact fix for each one.
What does invalid signature actually mean?
A JWT signature is created by taking the header and payload, encoding them and signing them with a secret key. When you verify a token the server recreates this signature and compares it to the one in the token. If they don't match — invalid signature error.
// JWT structure header.payload.signature // Verification process 1. Take the header + payload from the token 2. Sign them with your secret key 3. Compare result with the signature in the token 4. If they match → valid ✅ 5. If they don't → invalid signature ❌
The 5 most common causes
1. Wrong secret key
The most common cause. The token was signed with one secret but your server is trying to verify with a different secret. This happens after rotating secrets, environment variable mismatches or copy-paste errors.
// Token signed with jwt.sign(payload, "secret-v1") // But verified with jwt.verify(token, "secret-v2") // ❌ invalid signature // Fix — make sure both use the same secret // Check your environment variables! console.log(process.env.JWT_SECRET)
2. Token was modified after signing
If anyone modifies the header or payload after the token was signed — even changing one character — the signature becomes invalid. This is actually JWT working correctly — it's detecting tampering.
// Original token payload
{ "role": "user" }
// Someone modifies to
{ "role": "admin" }
// Signature no longer matches → invalid ❌
// This is JWT security working as intended ✅3. Algorithm mismatch
Token signed with HS256 but verified expecting RS256 — or vice versa. This is also a known security vulnerability called the algorithm confusion attack.
// Always specify the expected algorithm
// Never trust the algorithm from the token header!
jwt.verify(token, secret, {
algorithms: ['HS256'] // ← explicitly specify!
})
// Without this check an attacker could
// change alg to "none" to bypass verification4. Wrong key format for RS256
RS256 requires PEM formatted keys. A common mistake is passing the raw key string instead of the properly formatted PEM with headers and line breaks.
// Wrong — raw key string const publicKey = "MIIBIjANBgkqhkiG9w0BAQEF..." // Correct — PEM format const publicKey = `-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA... -----END PUBLIC KEY-----`
5. Encoding issues with the secret
If your secret is Base64 encoded but you pass it as a plain string — or vice versa — the signature will be invalid.
// If secret is Base64 encoded decode it first const secret = Buffer.from( process.env.JWT_SECRET_BASE64, 'base64' ) jwt.verify(token, secret)
Step by step debugging checklist
Inspect your JWT token instantly
See the exact header, payload and verify the signature of any JWT token.
Open JWT Decoder →