Decode a JWT and read its claims

Read a JWT's header, claims and expiry. Runs on your device.

How it works

  1. Paste the token
  2. Read the header and claims
  3. Check when it expires

What is inside a JWT

A JSON Web Token is three pieces of text joined by two dots: header.payload.signature. The header and the payload are JSON objects written in Base64URL, a form of Base64 that uses - and _ instead of + and /. The header names the algorithm, such as HS256 or RS256. The payload holds the claims, for example the subject (sub), the issuer (iss) and the times exp, nbf and iat. The signature is a run of bytes made with a key. This page reads the text as UTF-8, so a name like Zoë ✓ shows correctly. Decoding is tolerant: it accepts the standard Base64 characters + and / and = padding as well as the URL-safe form, it ignores a leading Bearer and it ignores line breaks and spaces inside the token. A JWT is encoded, not encrypted: anyone who has the token can read what is inside it.

What this page does not do

This page decodes a token. It does not check the signature, so it cannot tell you whether the token is genuine or has been changed. There is no field for a secret or a public key, on purpose: the page never asks for one. It does not create, sign or edit tokens, and it does not fetch anything from the network. A five-part token is an encrypted JWE, which cannot be read without its key, so the page stops with a message instead. An expired or not-expired status says nothing about whether a server will accept the token: the server may use a different clock, may allow some leeway, and may refuse the token for other reasons.

Reading the times

The claims exp, nbf and iat are numbers of seconds since 1970-01-01 00:00:00 UTC. The page shows them as UTC dates and compares exp and nbf with the clock of this device, read once each time the token is decoded. A token whose exp equals the current second counts as expired, because the current time must be before exp. A common mistake is writing milliseconds: 1700003600000 is read as seconds and lands in the year 55840, and the page adds a line saying that the number looks like milliseconds. Fractions of a second are dropped. The page applies no leeway, so a token that expired one second ago shows as expired.

Your token stays here

The token is decoded by your browser, in this tab. It is not sent to a server, not saved in this browser and not put in the page address. The page counts visits with Google Analytics, and no token data is in those counts. The Formatted view of a payload is rebuilt from the parsed JSON, so a number with 16 or more digits may be shown rounded; the Raw view shows the text exactly as it was in the token. A token that a service still accepts can grant access the way a password does. Paste live tokens only into pages you trust.

Frequently asked questions

Does this page check the signature?

This page decodes a token. It does not check the signature, so it cannot tell you whether the token is genuine or has been changed. It has no field for a key, so for an HS256 token signed with a shared secret or an RS256 token signed with a private key, the page shows only how many bytes the signature has.

Should I paste a production token here?

A token that a service still accepts can grant access the way a password does. Paste live tokens only into pages you trust. This page decodes the token in your browser and does not send it, save it or put it in the address bar, but a live token is still a credential. A token from a test system, or one that has already expired, carries less risk.

Why does it say expired when my app still works, or the reverse?

The page compares exp with the clock of this device, and a server may use its own clock and allow some leeway. This page applies none: a token with exp 1700001000 is expired at exactly 2023-11-14 22:30:00 UTC. A device clock that is a few minutes off can also change the answer.

What does alg none mean?

The header says the token has no signature protecting it, so anyone could write a header and payload like it. The page shows a notice when the header has alg none, in any letter case. It only reports what the header says and cannot tell you whether any service accepts such a token.

Why is a long number different in the Formatted view?

The Formatted view parses the payload as JSON, and JSON numbers become 64-bit floating-point values. The 20-digit number 12345678901234567890 appears as 12345678901234567000. Switch to Raw to see it as it was written in the token.

Can it decode an encrypted, five-part token?

No. A token with five parts separated by four dots is a JWE, an encrypted token. Its contents cannot be read without the key, and this page does not decrypt or ask for keys. The page stops and says so.