Aller au contenu principal

How to Decode a JWT

Paste the token into a decoder that runs in your browser, never one that asks for an upload; read the header and payload, check exp against the current time, and treat alg:none as an alarm. Decoding is reading, not verifying — only the issuer's key proves a token genuine. Every step below happens locally on the site's JWT Decoder.

100 % local
Vous voulez juste l’outil ? Ouvrez Décoder un JWTLit un JSON Web Token et explique chaque champOuvrir l’outil

Le guide ci-dessous n’est disponible qu’en anglais.

How to Decode a JWT explained

A JSON Web Token looks like wallpaper — three base64 segments joined by dots — and that disguise is exactly why decoding it deliberately, rather than squinting at it, is worth a procedure. Inside are a header that names the signing algorithm, a payload that names who the token belongs to and when it dies, and a signature that (if it is genuine) ties both to whoever issued it. The first two are readable by anyone; the third is checkable only with a key.

This page is the safe version of that reading job: five steps, each with a check, all of them performed in your own browser. The distinction matters because a JWT is a bearer credential — whoever holds it can use it. Pasting a live token into a random web page that decodes it server-side is handing that credential to the page's owner; pasting it into a tool that decodes locally hands it to nobody, and the Network panel is how you verify that claim instead of trusting it.

One expectation to set before the first step: a decoder can tell you what a token says and flag what looks wrong, but it cannot tell you a token is genuine. Authenticity is a signature question, and signature questions need the issuer's key. The last step is about where that verification actually happens — and why the answer is usually not this page.

All five steps run in the site's JWT Decoder — paste, read, and every claim arrives with its meaning attached.

For the full anatomy of the three segments, the guide to JWT structure explains each part with real examples before you inspect a live one.

The steps

  1. Copy only the token — nothing before or after it

    From the response header, the localStorage entry, or the request you are inspecting, copy exactly the three base64 segments: the piece that starts eyJ and ends at the last character of the third dot-separated segment. Strip any Bearer prefix, quotes and whitespace — a decoder can tolerate some of that, but pasting a clean token makes every downstream check unambiguous.

    Check: What you copied starts with eyJ (the base64 of {" — every JWT header does) and contains no spaces. That tiny check catches the commonest paste failure before any tool is involved.

  2. Paste it into a decoder that runs locally

    Open the JWT Decoder and paste. The header and payload decode instantly, in the tab — no upload, and the Network panel will show no request carrying the token. This is the step where the safe and unsafe versions of this procedure diverge: a server-side decoder has seen your token; a local one has not, because it never leaves your machine.

    Check: Two JSON objects appear — header first, payload below — with no error between them. If the decoder reports invalid base64 or broken JSON, the token was truncated or mangled in copying; re-copy from the source.

  3. Read the header — the algorithm sets the threat model

    The header's alg names how the token was signed: HS256 means a shared secret, RS256 or ES256 means a key pair where only the issuer holds the private half, none means unsigned. The tool flags alg:none loudly, because an unsigned token is a claim anyone could have written — accepting one is not a mistake, it is a policy failure. Note the alg now; step five needs it.

    Check: The alg row shows a real algorithm (HS256, RS256, ES256 are the common three) and never none. If it does show none, stop: the token proves nothing about itself, whoever issued it needs to hear about it.

  4. Read the payload — and check exp against real time

    The payload's claims are the token's whole story: sub names who it belongs to, iss names who made it, aud names who may accept it, and exp is the moment it dies — decoded into a real date and time by the tool, not the 1735689600 you would have to convert yourself. The tool also raises advisories: an expired token, one with no exp at all, one whose nbf sits in the future because the issuer's clock is ahead.

    Check: The exp row shows a date you can reason about — "expired 4 hours ago" or "expires in 11 minutes" — and the advisory list matches what you see. A token with no exp deserves suspicion: it never expires on paper.

  5. Verify with the issuer — not with the decoder

    Decoding proves nothing about genuineness: the signature segment is only checkable against a key, and the key belongs to the issuer. In practice verification happens where the key lives — your backend, an API gateway, your identity provider's library — not in a browser tab. If you are debugging why a service rejected a token, take the decoded claims to that service: an exp that already passed, an aud that does not match, or a kid the key cache has not picked up explain most rejections.

    Check: You can name, for the token in front of you, who must verify it (the service that accepted it) and what that service checks (signature against the issuer's key, plus exp, nbf and aud). If you cannot, the guide to JWT structure has the missing piece.

Decode and verify are different verbs

Decoding is base64 and JSON parsing — reading. Verification is a cryptographic operation — checking the signature against a key only the issuer holds. A decoder that showed you a green "valid" badge would be lying, because it can never have the issuer's private key, and even for public-key algorithms the check belongs to the accepting service, which knows which key and which audience apply.

This is why the tool never claims validity and instead explains what it sees: the algorithm, the claims, the expiry as a date, and the advisories a careful reader would raise. The reader who needs a verdict — the API receiving the token — is the only party with the materials to give one.

The claims worth reading every time

Four registered claims carry most of the story. exp: when the token dies — the single most useful row on the page. sub: who the token is about, usually a user or service identifier. iss and aud: who issued it and who may accept it — a token issued for one API is often rejected by another, and the rejected side is not malfunctioning, it is reading aud correctly.

Custom claims (roles, scopes, tenant ids) sit alongside and are decoded the same way, but treat them as claims, not facts: they are only as trustworthy as the signature behind them, which the decoder has not checked. iat (issued at) and nbf (not before) round out the timeline claims and explain the "token not yet valid" class of errors, which are almost always clock skew.

What a decoder can flag — and what only the server can know

The advisory layer catches what the payload admits on its face: alg:none, an empty signature segment, an exp in the past, a token with no exp at all, an nbf in the future. These are the defects that are visible without any key, and they are worth reading even when the token "works" — a system that accepts an expired token is a system you want to know about.

What no browser tool can tell you: whether the signature actually verifies, whether the issuer still recognises this session, whether the token was revoked. Those answers live behind the issuer's key and its records. The decoder's honesty is the boundary it draws between reading a token and trusting one.

Where tokens hide — and why that argues for local decoding

JWTs sit in Authorization headers, browser localStorage, URL fragments after login redirects, and application logs — places that are copied far more casually than files are. Every one of those copies is a live credential until it expires, which is why the decoding step of this procedure insists on a local tool: screenshots, tickets and chat messages containing decoded payloads are readable by anyone, but the raw token itself should travel nowhere except to the services meant to verify it.

The practical habits follow: decode locally, redact before sharing (the payload in a screenshot is usually enough to debug), and when a token must move for debugging, move it through the channel the issuer would consider acceptable — not a public paste site.

Frequently asked questions

Is it safe to paste my JWT into this decoder?

Yes, because the decode happens in your browser — the token is parsed by local code and never transmitted anywhere. You do not have to take that on faith: open DevTools, open the Network panel, paste a token, and observe that no request carries it. The site's Content-Security-Policy forbids outbound connections by construction, so even a bug could not exfiltrate it.

Can decoding tell me whether a token is valid?

No, and a decoder that claims to is misleading you. Validity is a signature question — the token must be checked against the issuer's key, plus the exp, nbf and aud policies of the service that receives it. A decoder shows you what the token says and flags surface defects (expired, unsigned, missing exp); the verdict belongs to the verifier that holds the key.

What does alg:none mean and why is it dangerous?

It means the header declares no signing algorithm — the signature segment should be empty, and the token's contents are a claim anyone could have written. Algorithms like HS256 exist precisely so that tampering is detectable; alg:none removes that guarantee. A decoder flags it loudly because accepting such a token is a known vulnerability class, not a formatting quirk.

Why does my token show as expired when the app still works?

Because the app refreshed it. Short-lived access tokens expire on purpose and are exchanged for new ones behind the scenes, usually with a refresh token; what you copied was probably already a retired generation. Decode the token the app is sending now and its exp should be in the future — if it is not, the service accepting it is not checking expiry, which is worth knowing.

What are exp, iat and nbf measured in?

Seconds since 1 January 1970 UTC — Unix time — which is why a raw payload shows them as ten-digit numbers like 1735689600. The decoder converts each into a real date and time and expresses the relationship to now ("expired 4 hours ago", "expires in 11 minutes"), which is the form a human can actually act on.

Can I share a screenshot of a decoded token?

The decoded header and payload are usually fine — they are readable by design and a screenshot showing claims is how most debugging happens. What must never be shared is the raw token itself: it is a bearer credential, and whoever holds it can use it until it expires. Redact signature segments and any identifiers you would not put in a ticket, and keep the full token out of screenshots entirely.