Skip to content
Tresna

JWT Decoder

Paste a JSON Web Token to read its header and claims. Expiry times are shown as real dates, and unsigned tokens are called out.

token

Example
26 B7 claims261 chars

header

{
  "alg": "HS256",
  "typ": "JWT"
}
HS256

payload

Reading the expiry now that the page has loaded.

This tool reads the token. It does not check the signature, so nothing here proves who issued it or that it has not been altered. Only the server that holds the key can do that.

Claims found in the payload of this token, with an explanation and a status for each.
ClaimValueMeaningStatus
isshttps://auth.example.comIssuer. Who created the token.
subuser_123Subject. Who or what the token is about.
audapiAudience. Which service the token is intended for.
exp20934560002036-05-03T19:33:20ZExpiration. After this moment the token must be rejected.
iat18933792002029-12-31T02:40:00ZIssued at. When the token was created.
scoperead write2: read, writeScopes. Space-separated permissions this token grants.
nameAda LovellaceThe user's display name.
Raw payload JSON
{
  "iss": "https://auth.example.com",
  "sub": "user_123",
  "aud": "api",
  "exp": 2093456000,
  "iat": 1893379200,
  "scope": "read write",
  "name": "Ada Lovellace"
}
checking7

Decoded. Algorithm HS256. Reading the expiry.

Runs in this browser tab. Nothing is uploaded, and the token is not stored or logged.

How to use this tool

A JSON Web Token is three base64url strings separated by dots. The first is a header, the second is a payload of claims, and the third is a signature. This tool reads the first two and turns the timestamps into dates you can read. It does not check the signature, and it says so on the page rather than in a footnote.

  1. 1Paste the token. A `Bearer ` prefix is fine to include; it is stripped for you.
  2. 2Read the summary above the claims, which covers the token's own expiry.
  3. 3Check the status column. Anything other than `Normal` needs a second look.
  4. 4Copy the header or the payload to paste into the JSON Formatter or an editor.

What decoding does, and what it does not

Base64url is an encoding, not an encryption. Anyone can turn the first two parts back into readable JSON, which is exactly what this page does. The payload of a JWT is not confidential, and a well-built one says so on its face.

The signature is a different matter. It is produced with a key only the issuer holds, and verifying it is what proves the token is genuine and unaltered. This tool has no key, so it does not verify, and no output here should be read as saying a token is trustworthy.

The three parts

PartContainsReadable here
HeaderThe signing algorithm, and sometimes a key id or a token type.Yes
PayloadThe claims: who issued it, who it is for, when it expires, and whatever the application added.Yes
SignatureBytes proving the first two were signed by the holder of the private key.Length only

A token with five parts is not a JWT but a JWE, which is encrypted. Its contents genuinely cannot be read without the decryption key, and this tool will say so rather than showing you something meaningless.

The claims worth knowing

These are defined by the JWT specification. Anything else in the payload is specific to whoever issued the token, and its meaning cannot be guessed from the name.

ClaimNameWhat it means
issIssuerWho created the token.
subSubjectWho or what the token is about. Usually a user id.
audAudienceWhich service is meant to accept it.
expExpirationAfter this moment the token must be rejected.
nbfNot beforeBefore this moment the token must be rejected.
iatIssued atWhen the token was created.
jtiJWT idA unique value, so a token can be identified or revoked.

`scope` and `scp`, both space-separated lists of permissions, are not part of the core specification but are near-universal in OAuth 2.0 tokens, so they are shown with their values spelled out.

Unsigned tokens, and why they are flagged

A header of `alg: none` means the token declares itself to carry no signature. There is nothing to forge, because there is nothing to check: anyone can write one. Libraries have historically differed on whether to accept them, which is precisely why a token like that should never be treated as authenticated.

This page marks that case in red, separately from the claim table, because it is a property of the token as a whole rather than of any one claim.

Timestamps, and the millisecond trap

A `NumericDate` is a number of seconds since 1 January 1970, and `exp` is the one people get wrong most often. A handful of issuers send milliseconds instead, which is off by a factor of a thousand.

When a value is far too large to be a plausible number of seconds, this tool assumes milliseconds and says so next to the date, rather than quietly showing you 1970 or a year in the thirty-thousands.

1893456000    2030-01-01T00:00:00Z   seconds  (correct)
1893456000000  2030-01-01T00:00:00Z   milliseconds, and wrong
The same expiry, written both ways.

Decoding by hand

Useful once, to see that nothing magic is happening. Take the first part, convert it from base64url by replacing `-` with `+` and `_` with `/`, add the padding that was stripped, and decode the result as UTF-8.

TOKEN='eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9'
echo "$TOKEN" | cut -d. -f1 | tr '_-' '/+' | base64 -d 2>/dev/null
echo "$TOKEN" | cut -d. -f2 | tr '_-' '/+' | base64 -d 2>/dev/null
Decoding a JWT in three shell commands.

The Base64 Decoder on this site does the same thing with the padding handled for you.

Frequently asked questions

Does this verify the token's signature?
No. It has no key to verify against, so it cannot. A token that decodes cleanly here may still be forged, expired, or signed by someone you do not trust. Only the server holding the signing key can answer that.
Is it safe to paste a token here?
The token never leaves your browser, and nothing is stored or logged. But a live access token is a credential: anyone holding it can act as you. Paste one you are finished with rather than a current session token.
Why does my token have five parts?
That is a JWE, an encrypted token, not a JWT. Its contents are genuinely unreadable without the decryption key, so there is nothing to decode.
What does alg: none mean?
The token declares that it carries no signature. There is nothing to verify, so anyone can create one, and it proves nothing about who sent it. This page flags it explicitly.
Why is my expiry date in 1970, or in the year 30000?
Almost always the seconds-versus-milliseconds mistake. The spec says seconds; some issuers send milliseconds. When the value is implausibly large this tool reads it as milliseconds and labels it as having done so.
Can I use this to check whether a session is still valid?
You can read what the token claims about itself, including whether its own expiry has passed. Whether the server still honours it is a separate question that only the server can answer.