How to Decode a JWT Token
Read any token's claims in seconds — and check exp first, because that's usually the bug.
Paste the token into a client-side JWT decoder to read its header and payload. A JWT is three Base64url-encoded parts separated by dots: header.payload.signature — the payload is encoded, not encrypted, so anyone holding the token can read every claim. When a login fails, check the exp claim first: an expired token is by far the most common cause.
| Claim | Meaning | Watch for |
|---|---|---|
exp | Expiry time | 10-digit seconds, not 13-digit ms |
iat | Issued at | Clock skew between servers |
nbf | Not valid before | Token rejected as 'too early' |
iss | Issuer | Must match your API's expectation |
aud | Audience | Wrong environment's token |
sub | Subject (user ID) | Usually who the token is for |
alg | Signing algorithm (header) | none is an attack |
Decoding is not verifying
This distinction causes real security bugs. Decoding just Base64-reverses the payload — anyone can do it, no key needed. Verifying checks the signature against a secret or public key to prove the token wasn't forged or altered.
The consequence: never trust a decoded claim in your backend without verifying the signature first. An attacker can craft any payload they like — {"sub": "admin", "role": "superuser"} — and it decodes perfectly. Only the signature check catches it.
Related and worse: if your library accepts "alg": "none", an attacker strips the signature entirely and walks in. Any decent library rejects this now, but pin your expected algorithm explicitly rather than trusting the token to tell you which one to use — letting the attacker choose the verification algorithm is the whole vulnerability.
Why 'my token works locally but not in production'
Almost always one of four things, in rough order of likelihood:
- Expired. Check
exp. Dev tokens often have long lifetimes; production ones might last 15 minutes. - Wrong
audoriss. A staging token presented to the production API. The signature is valid, the token is real, and it's still rejected. - Clock skew. If the server's clock is ahead, a freshly issued token can fail
nbforiatchecks. Most libraries allow a small leeway; if yours doesn't, that's the bug. - Wrong key. Different environments sign with different secrets. Signature verification fails and the message is usually unhelpful.
Decode both a working and a failing token and diff the claims. The difference is nearly always visible immediately.
Don't put secrets in a JWT
Because the payload is readable by anyone holding the token, a JWT should carry identity and authorisation claims — user ID, roles, expiry — and nothing confidential.
Things that don't belong in a JWT: passwords or password hashes, API keys, full personal records, internal database IDs you'd rather not expose, anything under privacy regulation. Users can read all of it in a decoder in five seconds, and so can anyone who intercepts the token.
Keep tokens short-lived (15–60 minutes) with a refresh token for renewal. A leaked JWT is valid until it expires — there's no revocation list unless you build one — so expiry is your damage control.
Tools used in this guide
Frequently asked questions
Is it safe to decode a JWT online?
Only with a client-side decoder, and preferably not with a live token at all. A JWT is a bearer credential — whoever holds it can act as that user until it expires. A server-side decoder receives your token. SnoopTool's JWT Decoder decodes entirely in your browser and transmits nothing, but using an expired or test token is still the safer habit.
Is a JWT encrypted?
No. A JWT is Base64url-encoded, which is reversible by anyone with no key at all. The signature prevents tampering, not reading — every claim in the payload is visible to whoever holds the token. This is why you must never put passwords, API keys or confidential personal data in a JWT payload.
Why is my JWT being rejected?
Check exp first — an expired token is the most common cause by a wide margin. Then check that iss and aud match what your API expects (a staging token sent to production is a classic). Then consider clock skew between servers, and finally a key mismatch between environments. Decode a working token and a failing one side by side; the difference is usually obvious.
What is the difference between decoding and verifying a JWT?
Decoding reverses the Base64 encoding to reveal the claims — anyone can do it without a key. Verifying checks the cryptographic signature against a secret or public key to prove the token was genuinely issued and not altered. Never trust decoded claims in a backend without verifying: an attacker can craft any payload they want, and it will decode perfectly.
Need a tool we don't have yet?
Tell us what you're trying to do. We build the most-requested tools first — every SnoopTool utility is free, runs in your browser, and needs no sign-up.