Skip to content
WebTricks

JWT decoder

Decode a JSON Web Token to inspect its header and payload. Decoding happens locally — your token is never sent anywhere.

Header
{
  "alg": "HS256",
  "typ": "JWT"
}
Payload
{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022
}

What this JWT decoder does

Paste a JSON Web Token and the tool splits it on the dots, Base64URL-decodes the first two parts and pretty-prints them as JSON. The header tells you the signing algorithm and token type, the payload holds the claims, and if an exp claim is present you get a human-readable UTC expiry line above them. The signature is not checked — this is a reading tool for debugging auth flows, not a validator. Everything runs locally; the token is never transmitted.

How to use it

  1. Paste the token into the Token box. Whitespace around it is ignored; the sample is the well-known HS256 example from jwt.io.
  2. The Header and Payload panels update as you type.
  3. If the payload has an exp claim, an Expires … line appears with the date in ISO 8601 (UTC). Compare it with now to see whether the token is still valid.
  4. Use Copy on either panel to grab the formatted JSON.

If you see “Could not decode token”, the input is not a JWT (many session cookies and API keys are opaque strings, not JWTs) or a character was corrupted in transit.

Anatomy of a JWT

A signed JWT (JWS) is three Base64URL strings joined by dots: header.payload.signature.

PartContentExample (decoded)
HeaderAlgorithm and type, sometimes a key ID{"alg":"HS256","typ":"JWT","kid":"2024-01"}
PayloadThe claims — registered, public and private{"sub":"1234567890","name":"John Doe","iat":1516239022}
SignatureHMAC or digital signature over header.payload32 raw bytes for HS256, shown as 43 Base64URL characters

Base64URL is standard Base64 with + and / replaced by - and _ and the trailing = padding removed, so a token survives inside URLs and HTTP headers without further encoding. A five-part token (four dots) is a JWE, an encrypted JWT — its payload cannot be read without the key, and this tool will not decode it.

Standard claims to look for

ClaimMeaningFormat
issIssuer — who minted the tokenString or URL, e.g. https://accounts.example.com
subSubject — the user or principalString, typically a user ID
audAudience — who should accept itString or array of strings
expExpiration timeUnix seconds (not milliseconds)
nbfNot valid beforeUnix seconds
iatIssued atUnix seconds
jtiUnique token ID, used for revocation listsString

Timestamps are seconds, so 1516239022 is 2018-01-18T01:30:22Z. If a value looks ten times too long (13 digits) somebody serialized milliseconds, and most libraries will treat the token as valid for thousands of years. Use the timestamp converter to check any claim beyond exp.

Decoding is not verifying

The payload you see is exactly what a server would see before checking the signature — and that is the point of the signature. Reading "role":"admin" in a token says nothing about whether the token is trusted. A proper check on the server does all of the following:

  1. Verify the signature with the expected key and the algorithm you expect, never the one in the header.
  2. Reject if exp is in the past or nbf is in the future (allow a small clock skew, usually 30–60 s).
  3. Check iss and aud match your service.
  4. Optionally check jti against a revocation list.

Skipping step 1 or trusting the header’s alg is how most real-world JWT vulnerabilities happened. Algorithms you will typically meet: HS256 (shared secret, symmetric), RS256 (RSA public/private key), ES256 (ECDSA P-256), EdDSA (Ed25519).

FAQ

Does this verify the signature?

No. Decoding only reads the Base64URL-encoded header and payload; verifying requires the server's secret (HS256) or public key (RS256/ES256) and must happen on the server. A token that decodes fine can still be forged or expired.

Is it safe to paste my token here?

Yes. Decoding runs entirely in your browser with no network request, so the token never leaves the page. Still, treat access tokens like passwords and avoid pasting production tokens into tools that send them to a server.

Why can anyone read my JWT payload?

Because a JWS token is signed, not encrypted. The payload is plain JSON in Base64URL, which is why you should never put passwords, card numbers or secrets in claims. If you need confidentiality, use JWE (encrypted JWT) or keep the data server-side.

What does the "Expires" line mean?

It converts the exp claim (seconds since the Unix epoch) to an ISO 8601 UTC timestamp. Compare it with the current time — if it is in the past the token is expired. If the payload has no exp claim the line is not shown.

Why does it say it could not decode the token?

Either the parts are not valid Base64URL (a character got mangled while copying, or you pasted an opaque session ID that is not a JWT) or the decoded part is not JSON. Make sure you pasted the whole token with its two dots.

What is the alg none attack?

Some libraries once accepted tokens whose header said "alg":"none" and skipped signature checks entirely. Always pin the expected algorithm on the server and reject any other value, no matter what the header claims.