JWT Decoder

Read a token’s header and claims, and see what it says about itself. Decoding, not verification.

Decoding is not verification. The two readable segments of a JWT are just base64 — anyone can read them and anyone can write them. Only the signature makes a token trustworthy, and checking it needs the key. This page does not have the key, does not ask for one, and makes no claim about whether the token is genuine.

A Bearer prefix is stripped automatically. Nothing you paste leaves this page.

Three segments, one of which matters

A JWT is three base64url strings joined by dots. The first two are JSON you can read; the third is a signature over the first two.

eyJhbGciOiJIUzI1NiJ9  .  eyJzdWIiOiIxMjM0In0  .  4fXK...
      header                    payload            signature

The header says which algorithm signed it. The payload carries the claims. Neither is encrypted — the base64 is transport encoding, not concealment, and anyone holding the token can read both in about a second.

The signature is the only part doing security work. It proves the first two segments were produced by someone holding the signing key and have not been modified since. Without checking it, a JWT is a self-describing text file with no more authority than any other string a client sent you.

Which is why this page will not tell you a token is valid

Verification needs the key, and there is no version of “paste your signing secret into a web page” that is good advice. What the tool does instead is report what the token says about itself: whether it has expired, whether its not-before time has arrived, whether the algorithm is symmetric or asymmetric, and whether it claims to need no signature at all.

alg:none, and why it is instructive

The specification allows "alg": "none" — a token with no signature. The attack writes itself: take a legitimate token, edit the payload to claim whatever you like, set the algorithm to none, delete the signature, and send it.

A library that reads the algorithm out of the header and does what it says will accept this. The attacker chose the verification policy, because the policy was in the attacker-controlled part of the message.

The related version is algorithm confusion. A server verifying RS256 has the public key, which is not secret. Change the header to HS256 — a symmetric algorithm — and sign with that public key as the shared secret. A naive library uses the same key material for both and the forged token verifies.

Both are fixed the same way, and it is a general principle worth carrying elsewhere: the verifier must state which algorithms it accepts rather than asking the token.

What actually goes wrong in production

SymptomUsual cause
Rejected immediately after issueClock skew. The iat or nbf is a few seconds ahead of the verifier’s clock. Allow a small tolerance.
Works locally, fails deployedDifferent signing key per environment — a staging token sent to production.
Valid signature, still rejectedThe aud or iss claim does not match what that service expects.
Works, then stops mid-sessionExpiry. Short-lived tokens need a refresh flow, and it is usually the missing piece.
Requests fail with headers too largeThe token outgrew the limit. Most servers cap headers around 8 KB, and browsers cap a cookie at 4 KB.

The revocation problem

The reason to use a JWT is that verification needs no database lookup — the token carries its own proof. That is also precisely why you cannot revoke one. Nothing is consulted at verification time, so there is nowhere to record that a token should stop working.

The options, none of them free:

  • Short expiry plus refresh tokens. The standard answer. Access tokens live minutes, refresh tokens are checked against a database and can be revoked.
  • A denylist. Check every token’s jti against a store of revoked ones — which reintroduces the lookup the format existed to avoid.
  • Rotate the signing key. Invalidates every token at once, including everyone else’s.

If you need immediate revocation of individual sessions more than you need stateless verification, an opaque session identifier backed by a store is the simpler design, and it is underrated.

Related

All three segments are URL-safe Base64, unpadded — which is why a segment often fails in a strict decoder. Once decoded the two readable parts are JSON. And for the credential the token stands in for, the strength checker covers the other end of the login.

JWT questions

Does decoding a JWT verify it?

No, and the distinction is the whole security model. The header and payload are base64url — reading them requires nothing. Verification means recomputing the signature with the key and comparing, which proves the token was issued by whoever holds that key and has not been altered since. A decoder without the key can tell you what a token claims; only verification tells you whether to believe it.

Is it safe to paste a real token into a website?

Into this page, yes — decoding happens in your browser and nothing is transmitted. But the instinct behind the question is a good one and worth keeping. A JWT usually is a live credential: anyone holding it can act as you until it expires. A decoder that posts it to a server has been handed a working session. Check where any tool does its work before pasting a production token into it.

Can I put secrets in a JWT payload?

No. The payload is signed, not encrypted — it is readable by anyone holding the token, including the user it was issued to. Signing guarantees the contents have not been changed; it does nothing to hide them. If you genuinely need a confidential payload, that is JWE, a different and considerably more involved specification. In practice the better answer is usually to keep the sensitive part on the server and put an identifier in the token.

What is the alg:none vulnerability?

The JWT specification permits an "alg" of "none", meaning an unsigned token. The attack is to take a valid token, change the payload to claim administrator, set alg to none, and drop the signature. A library that trusts the header's algorithm field will validate it — the token itself specified that no checking was required. Every major library has been patched, but the lesson generalises: the server must decide which algorithms it accepts, rather than letting the token nominate one.

How do I revoke a JWT before it expires?

You largely cannot, and this is the trade the format makes. A JWT is verifiable without a database lookup, which is what makes it fast — and it is also why nothing consulted at verification time knows you wanted it revoked. The workable answers are short expiry times with refresh tokens, a denylist of revoked identifiers checked on each request (which reintroduces the lookup you were avoiding), or rotating the signing key to invalidate everything at once.

Why is my token being rejected when it looks valid?

After expiry, the usual causes are clock skew between the issuer and the verifier, an audience or issuer claim that does not match what the server expects, or the token having been signed with a different key than the one the verifier holds — commonly a staging token used against production. The decoder above flags the timing problems it can see; the audience and key mismatches only the server can tell you about.

Last reviewed . Found something out of date? Tell us.