Skip to tool
ecech.
💻 Developer & Code

JWT Decoder That Reminds You Decoding Is Not Verifying

A JWT payload is base64, not encryption — anyone holding the token can read it. Decode the claims, check the expiry, and see what the token is really telling you.

This decodes, it does not verify. Anyone holding a token can read its claims — the payload is base64, not encryption. Only a signature check with the key proves a token is genuine, and that belongs on your server. Decoding here happens in your browser and nothing is transmitted.

Algorithm

Status

Expires

Lifetime

Header

Payload



What the claims mean

Advertisement

How the calculation works

Three parts, and only one of them protects anything header payload signature base64, readable base64, readable the only proof which algorithm your claims, in plain sight needs the key to check Anyone can decode the first two. Anyone can write new ones. Only the signature says who made it. So nothing sensitive belongs in the payload, ever.

How to Use This Tool

Paste a token to read its header and payload. Timestamps are converted, the expiry is checked, and each standard claim is explained.

Decoding is not verifying

A JWT is three base64url segments joined by dots. The first two are encoded, not encrypted — base64 is a transport format, and reversing it takes no key and no effort. Anyone who obtains a token can read every claim in it: the user id, the roles, the email, whatever you put there.

The third segment is the signature, and it is the only part that proves anything. It says the token was produced by someone holding the signing key and has not been altered since. Checking it requires that key, which is why verification belongs on a server and never in a browser.

The practical rule: reading claims to decide what to display is fine. Reading them to decide what to permit is not, because a client-side decode cannot tell a genuine token from one somebody typed.

Never put secrets in a payload

This follows directly and is still a common mistake. A JWT payload is visible to the browser holding it, to every proxy and logging layer it passes through, to anyone who finds it in a URL, a browser history entry, a server log or an error report.

Put an identifier in the token and keep the sensitive data behind a lookup. If a claim would be a problem in a log file, it is a problem in a JWT.

The alg: none attack, in one line {"alg":"none","typ":"JWT"} attacker writes this header {"sub":"1","role":"admin"} and any payload they like (no signature at all) libraries that trusted alg skipped the check Fix: the server decides which algorithms are acceptable. The token does not get a vote.
The header is attacker-controlled, so it cannot be allowed to choose the verification method.

The standard claims

  • iss — issuer, who made the token. Verify it matches who you expect.
  • sub — subject, usually the user id.
  • aud — audience, who the token is for. A token issued for one service should be rejected by another, and checking this is frequently skipped.
  • exp — expiry, in seconds since 1970. After this the token should be refused.
  • iat — issued at.
  • nbf — not before; the token is invalid until this time.
  • jti — a unique id for the token, used to revoke or to prevent replay.

Note that all the time claims are in seconds, not milliseconds. Writing Date.now() straight into exp creates a token that expires in the year 58,000, which is a bug that never fails loudly.

Why you cannot easily revoke one

A JWT is verified by arithmetic on its signature, with no database involved. That is what makes it fast and stateless — and it means that once issued, a token is valid until it expires, whatever happens afterwards. Logging out, changing a password, or deleting an account does not invalidate tokens already in the wild.

The usual answers are short lifetimes with a refresh token, or a denylist of jti values checked on each request — which reintroduces the database lookup JWTs were meant to avoid. There is no free version of this trade-off, and choosing a long expiry because refresh is inconvenient is how it goes wrong.

Advertisement

Frequently Asked Questions

Is a JWT encrypted?
No. The header and payload are base64url encoded, which is a transport format, not encryption — reversing it takes no key. Anyone holding a token can read every claim in it. Only the signature is cryptographic, and it proves the token's origin rather than hiding its contents.
Can I verify a JWT in the browser?
You can decode it, but verifying it meaningfully requires the signing key, and putting that key in a browser gives it to everyone. Verification belongs on the server. Client-side you can read claims to decide what to display, never to decide what to permit.
Is it safe to put user data in a JWT payload?
Only data you would be comfortable seeing in a log file. The payload is visible to the browser, to any proxy or logging layer the token passes through, and to anyone who finds it in a URL or an error report. Put an identifier in the token and keep sensitive data behind a lookup.
What is the alg: none attack?
A token whose header claims no algorithm was used, with no signature attached. Libraries that read the algorithm from the token and acted on it would skip verification entirely and accept whatever claims the attacker wrote. The fix is that the server decides which algorithms are acceptable — the token does not get a vote.
Why is my JWT expiry wrong?
Usually because exp was set in milliseconds. All JWT time claims are in seconds since 1970, so writing Date.now() directly produces a token that expires tens of thousands of years from now. It never fails loudly, so it survives until someone checks.
How do I revoke a JWT?
You largely cannot, and that is the trade-off. Verification is arithmetic on the signature with no database involved, so a token stays valid until it expires regardless of logouts or password changes. The options are short lifetimes with refresh tokens, or a denylist of token ids checked per request — which reintroduces the lookup JWTs were meant to avoid.
Does my token get sent anywhere by this page?
No. Decoding is base64 and JSON parsing done in your browser. That matters, because pasting a live token into someone else's server hands them a working credential.

Related tools in Developer & Code

Browse all Developer & Code tools
A handwritten note reading ecech.com resting on the keyboard used to build the site.

Made by one person

ecech. is not a content farm. Every tool here is written and checked by hand, one at a time, by someone who wanted the tool to exist and could not find a version that showed its working.

No accounts and no sign-in, and nothing you type reaches a server — every calculation on this page runs inside your browser. The ads are served by Google and do set their own cookies, which is set out in full on the privacy page. More about the site.