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
header
{ "alg": "HS256", "typ": "JWT" }
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.
| Claim | Value | Meaning | Status |
|---|---|---|---|
| iss | https://auth.example.com | Issuer. Who created the token. | |
| sub | user_123 | Subject. Who or what the token is about. | |
| aud | api | Audience. Which service the token is intended for. | |
| exp | 20934560002036-05-03T19:33:20Z | Expiration. After this moment the token must be rejected. | |
| iat | 18933792002029-12-31T02:40:00Z | Issued at. When the token was created. | |
| scope | read write2: read, write | Scopes. Space-separated permissions this token grants. | |
| name | Ada Lovellace | The 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" }
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.
- 1Paste the token. A `Bearer ` prefix is fine to include; it is stripped for you.
- 2Read the summary above the claims, which covers the token's own expiry.
- 3Check the status column. Anything other than `Normal` needs a second look.
- 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
| Part | Contains | Readable here |
|---|---|---|
| Header | The signing algorithm, and sometimes a key id or a token type. | Yes |
| Payload | The claims: who issued it, who it is for, when it expires, and whatever the application added. | Yes |
| Signature | Bytes 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.
| Claim | Name | What it means |
|---|---|---|
| iss | Issuer | Who created the token. |
| sub | Subject | Who or what the token is about. Usually a user id. |
| aud | Audience | Which service is meant to accept it. |
| exp | Expiration | After this moment the token must be rejected. |
| nbf | Not before | Before this moment the token must be rejected. |
| iat | Issued at | When the token was created. |
| jti | JWT id | A 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 wrongDecoding 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/nullThe 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.