How-to guide

How to Fix JWT Signature and Expiry Errors

An invalid signature means the token was verified against a different key from the one that signed it, or with a different algorithm. Expired means the exp claim is in the past, sometimes only because of clock skew between servers. Malformed means the string is not three dot-separated Base64url segments. Decoding a token proves none of these.

JWT Decoder

Read a JSON Web Token header, payload and expiry.

Open the tool

Verification failures are rarely subtle once you separate the three rejections. Each one fails at a different stage: malformed fails before any crypto happens, invalid signature fails during it, and expired fails after the signature has already been accepted.

Decoding is not verifying. A decoder reads the header and payload without checking anything, which is exactly why it is useful for diagnosis — you can see the claims of a token your server is rejecting, including which key it says it was signed with.

Step by step

  1. Decode the token and read the header

    The alg claim tells you which algorithm signed it and kid, when present, tells you which key. A token signed with RS256 will never verify against an HS256 secret, and that mismatch is a common result of copying configuration between services.

  2. Check how the secret is being interpreted

    For HMAC algorithms the secret is a byte string. If one side treats it as UTF-8 text and the other Base64-decodes it first, the two produce different keys from the same configuration value and every signature fails. This is the most common cause of invalid signature.

  3. Compare exp against real time

    exp and iat are Unix timestamps in seconds, not milliseconds. Convert them and compare with the current time. A token that expired seconds ago on a server whose clock has drifted is a clock problem, not a token problem.

  4. Confirm the token came from this environment

    Staging and production almost always use different signing keys. A token pasted from the wrong tab, or a cached token surviving a key rotation, produces exactly the same invalid signature error as a genuine attack.

  5. Count the segments before anything else

    A malformed error means the string is not three Base64url segments separated by dots. Check for a Bearer prefix that was not stripped, a truncated value from a database column that was too short, or whitespace introduced by copying.

Example

The three segments of a JWT. Only the first two are readable; the third is the signature over them.

Token

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxIiwiZXhwIjoxNzAwMDAwMDAwfQ.signature

Decoded header and payload

header:  { "alg": "HS256", "typ": "JWT" }
payload: { "sub": "1", "exp": 1700000000 }

Frequently asked questions

Why does my JWT show an invalid signature?
The verifying key does not match the signing key, or the algorithms differ. The subtle version is a secret that one service reads as raw text while the other Base64-decodes it first — same configuration value, two different keys, and every signature fails.
My token has not expired but is rejected as expired. Why?
Clock skew. exp is compared against the verifying server's clock, so a server running a minute fast rejects tokens that are still valid elsewhere. Most libraries allow a small leeway setting, typically thirty to sixty seconds, for exactly this.
Can I trust a JWT payload after decoding it?
No. Decoding reads Base64url and checks nothing. Anyone can alter the payload and re-encode it; only signature verification with the correct key proves the token is genuine. Never make an authorisation decision from a decoded payload alone.
Is it safe to paste a token into a decoder?
Only if the decoding happens in your browser, as it does here — nothing is transmitted. Treat a live token as a credential regardless: anyone holding it can act as that user until it expires, so prefer an expired or test token when sharing.
What does a malformed token error mean?
The value is not three Base64url segments separated by two dots. Common causes are an unstripped "Bearer " prefix, truncation by a database column that was too short, or line breaks introduced when the token was copied.

Tools used in this guide

All tools →
All guides →

Last reviewed .