taptools/blog/JWT Invalid Signature
JWTMay 15, 2026 · 6 min read

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 verification

4. 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

Decode the token header — check the alg field matches what your server expects
Verify the secret in your environment matches the one used to sign
Check no middleware is modifying the token before verification
For RS256 — verify you are using the correct public key
Check the token has not been URL decoded/encoded incorrectly
Verify the token was not copied with extra whitespace or characters

Inspect your JWT token instantly

See the exact header, payload and verify the signature of any JWT token.

Open JWT Decoder →