| Issued at | — |
| Expires | — |
| Not before | — |
| Status | |
| Valid for | — |
Header
Payload
Signature
Claims
| Claim | Meaning |
|---|
This tool decodes only. It does not verify the signature, so a decodable token is not necessarily a trustworthy one.
A JSON Web Token looks like noise until you split it. Decoding a token here shows you the header, the payload and the raw signature, then explains the registered claims in plain language — what exp means, whether it has already passed, and how long the token was issued for.
There is one thing this tool deliberately does not do, and it is the most important sentence on this page: it does not verify the signature. Decoding unpacks the readable parts. It cannot tell you whether the token is genuine, and no browser-only tool can, because verification requires the secret or public key that only the issuer holds.
How to use this tool
- Paste the token into the box. A leading
Bearerprefix and surrounding whitespace are removed for you, so a copy straight out of an Authorization header works without editing. - Click Decode. The header and payload appear as formatted JSON and the signature is shown in its raw encoded form.
- Read the timing table to see when the token was issued, when it expires, and whether that moment has already passed according to your clock.
- Check the Claims table, which names each registered claim and explains what it asserts. This saves looking up the abbreviations every time.
- Copy payload JSON takes just the claims, for pasting into code or a bug report.
Header, payload, signature — what each part is for
A JWT is three base64url segments joined by dots. The structure is simple, and understanding which part is trustworthy is the whole game.
The header is a small JSON object, almost always two fields: alg, naming the signing algorithm, and typ, which is JWT. Some tokens add kid, a key identifier telling the verifier which of several published keys to use. The header is not secret and not signed separately — it is covered by the signature along with the payload.
The payload is the claims: statements about the subject. It is base64url-encoded JSON and readable by anyone holding the token. This is the single most common misunderstanding about JWTs. Encoding is not encryption, and a token you hand to a browser is a token the user can read in full.
The signature is computed over the first two segments with the issuer key. It proves the header and payload have not been altered since signing. It does not hide them, and it does not stand alone — validation also has to check exp, iss and aud against your own expectations.
Base64url encoding is base64 with - and _ replacing + and /, and usually the = padding removed, because those characters survive URLs and headers without escaping. The decoder normalises this automatically, so segments copied out of a URL work as-is.
The registered claims, and what each one actually asserts
RFC 7519 defines a set of optional registered claims. They are short because tokens travel in headers and every byte counts, which is exactly why they need looking up.
iss— issuer. Who created the token. Your verification must check this against an expected value; a token signed by a legitimate but different service is still the wrong token.sub— subject. Who the token is about, typically a user identifier.aud— audience. Who the token is intended for. This is the claim most often left unchecked, and skipping it means a token minted for one service can be replayed against another that shares the signing key.exp— expiration time, as a Unix timestamp in seconds. The single most important claim to validate.nbf— not before. The token is invalid before this moment, used to issue a token that becomes active later.iat— issued at. Not a validity constraint by itself, but useful for computing age and for rejecting implausibly old tokens.jti— JWT ID. A unique identifier for this token, which allows a server to maintain a revocation list.
All time claims are numeric seconds since the Unix epoch, never milliseconds and never ISO strings. A token with exp in the region of 1.7 billion is valid; one with a value around 1.7 trillion has been written in milliseconds by mistake, which places expiry roughly fifty thousand years in the future.
Why decoding is not verification
This deserves its own section because it is the mistake that turns a decoder into a security incident.
A signature verifies only if you check it with the right key. Anyone can create a token with any payload they like, sign it with a key they control, and the result will decode perfectly here. Every field will look plausible. Nothing about a successful decode indicates that the token is real.
The classic attack against naive implementations is algorithm confusion. The token header declares alg, and a server that trusts that field is trusting the attacker. Three variants matter:
alg: "none"— the token declares itself unsigned. Some libraries historically honoured this, accepting any payload without checking anything. This tool flags it when it appears.- HS256 where RS256 was expected — an attacker signs with a public key as if it were an HMAC secret. If the server uses the same code path for both algorithms, verification succeeds.
- Key confusion through a
kidpath traversal — the key identifier is used to load a file from disk, and the attacker supplies../../dev/nullto get an empty key.
The defence is uniform and well established: pin the expected algorithm on the server, never read it from the token. Verify iss, aud and exp explicitly. Treat the header as untrusted input, because it is.
Reading the expiry correctly
The status indicator compares the current time on your device against exp. That is a convenience, not a security verdict, and it splits into three cases worth distinguishing.
Not expired means your clock currently sits before the claim. If your device clock is wrong — a laptop that has been suspended, a container without NTP — the indicator is wrong with it. Clock skew is also real between services: the spec allows a small leeway on either side of exp, commonly thirty to sixty seconds, precisely because clocks disagree.
Expired means the moment has passed locally. Note that an expired token may still be accepted by a misconfigured server that does not check. That is a server bug, and the decoder showing an expiry is the easiest way to notice it.
No expiry claim is the case to be suspicious of. A token without exp never expires. If it is also a long-lived access token rather than a refresh token, it is a credential that cannot be recalled except by rotating the signing key, which invalidates every other token at the same time.
Lifetime is worth glancing at too. Access tokens are commonly measured in minutes, refresh tokens in days or weeks. An access token with a lifetime measured in months is worth raising with whoever issued it.
Common formats you will meet
Most tokens in the wild are one of three shapes, and the header tells you which.
JWS — a signed token, the ordinary case. Three segments, algorithm HS256, RS256 or ES256. The payload is readable, the signature makes it tamper-evident.
JWE — an encrypted token. Five segments rather than three, because it carries an encrypted content key alongside the ciphertext. Here the payload genuinely is confidential, and a decoder will show you nothing but ciphertext. If you paste a five-part token and the payload looks like binary, that is why.
JWT with a nested JWS — a signed token whose payload is itself a signed token, occasionally used when two parties each need to sign. Rare, and confusing when you meet it: the payload decodes to another complete token rather than to claims.
One more variant worth recognising is the opaque token, which is not a JWT at all — just a random string the server looks up in a database. It has no structure to decode, and that is a legitimate design choice rather than a fault.
What this decoder tells you, and what it cannot
| Question | Answered here? | Why |
|---|---|---|
| What claims does this token carry? | Yes | The payload is base64url JSON and decodes locally |
| When does it expire? | Yes | The exp claim is converted and compared to your clock |
| Which algorithm signed it? | Yes, as declared | Read from the header, which is attacker-controlled |
| Is the signature valid? | No | Verification needs the secret or public key held by the issuer |
| Has this token been revoked? | No | Revocation lives in a server-side list, not in the token |
| Should I trust the user identity in it? | Not from here | Identity is trustworthy only after signature, audience and issuer checks |
| What is inside an encrypted JWE? | No | The payload is genuinely ciphertext and needs the decryption key |