JWT Decoder

Paste a JSON Web Token to read its header and payload as formatted JSON, with the algorithm and any expiry shown in plain language. Decoding happens in your browser — the token is never uploaded.

Paste a JWT above and press Decode JWT.

What a JWT is

A JSON Web Token (JWT) is a compact, URL-safe token made of three Base64url-encoded parts joined by dots: header.payload.signature. The header says how the token is signed, the payload carries the claims (data) and the signature lets a server verify the token wasn't tampered with.

header . payload . signature Base64url-decode header & payload

This decoder splits the token, Base64url-decodes the first two parts and pretty-prints them as JSON. It does not verify the signature, because that requires the secret or public key — which you should never paste into any website.

Worked example

For the sample token, the parts decode to:

Header: {"alg":"HS256","typ":"JWT"} — signed with HMAC-SHA256.
Payload: {"sub":"1234567890","name":"Calcool","iat":1700000000}.
iat (issued-at) 1700000000 is shown as a readable date.

Signature and security

Anyone can read a JWT's payload — it's only encoded, not encrypted — so never store secrets in it. The signature is what proves authenticity, and only the server with the key can validate it. Standard claims include exp (expiry), iat (issued at), sub (subject) and iss (issuer); this tool flags whether the token is expired based on exp.

Tip: need to decode plain Base64 instead? Use the Base64 encoder / decoder.

Registered claims you'll actually see

RFC 7519 defines seven registered claim names. They're optional, but interoperable tools agree on what they mean, so knowing them lets you read almost any token at a glance:

ClaimNameWhat it carries
issIssuerWho minted the token (e.g. https://accounts.google.com). Your code should check this matches the provider you trust.
subSubjectThe user or entity the token is about — usually a stable user ID, not an email.
audAudienceWho the token is for. Reject the token if your service isn't in aud.
expExpirationUnix seconds after which the token is invalid. Always enforce server-side.
nbfNot beforeToken is invalid until this time — useful for tokens issued ahead of activation.
iatIssued atWhen it was created. Handy for detecting tokens that are suspiciously old.
jtiJWT IDA unique identifier you can store to make a token one-time-use (replay protection).

Everything else in the payload is a private claim — name, email, roles, scope and so on. Those are app-specific and not standardised, so two providers may format them differently.

Reading the alg header — and the traps

The header's alg tells you (and the verifier) how the signature was produced. The three families you'll meet:

  • HS256 / HS384 / HS512 — HMAC with a shared secret. Both signer and verifier hold the same key. Simple, but the secret must stay on the server.
  • RS256 / RS384 / RS512 — RSA signatures. The issuer signs with a private key; anyone can verify with the public key. This is what OpenID Connect providers (Google, Auth0, Microsoft) use.
  • ES256 / ES384 — ECDSA, the same public/private idea as RSA but with shorter keys and smaller signatures.

Two classic, real-world vulnerabilities are visible right in the header, so it's worth knowing them:

alg: none — A token claiming "alg":"none" has no signature at all. Early libraries accepted these, letting attackers forge any payload. A correct verifier rejects none unless explicitly, deliberately allowed.
RS256 → HS256 confusion — If a server expects RS256 but a library lets the token choose the algorithm, an attacker can sign an HS256 token using the public RSA key as the HMAC secret. Always pin the expected algorithm server-side rather than trusting the header.

Troubleshooting a token that won't validate

When a backend rejects a JWT, decoding it here usually reveals which check failed:

SymptomLikely cause
"Token expired"exp is in the past. Compare it to the current Unix time; allow a small clock-skew window (typically 30–120 s).
"Invalid audience"aud doesn't list your service's client ID. Common when a token minted for one app is reused on another.
"Signature verification failed"Wrong key, wrong algorithm, or the token was modified. Decoding still works because decoding never checks the signature.
Decoder shows garbage / fails to parseA part isn't valid Base64url — often a copy-paste truncation, or someone pasted a Base64 (not Base64url) string with + and / instead of - and _.
When not to use a JWT: for sessions you need to revoke instantly (logout, ban), a stateless JWT is awkward — it stays valid until exp. A short expiry plus a server-side jti blocklist, or a plain database session, is often the better choice.

Frequently asked questions

Does this verify the JWT signature?

No. Verifying a signature needs the secret or public key, which you must never paste into a website. This tool only decodes the readable header and payload so you can inspect the claims.

Is a JWT encrypted?

No. The header and payload are Base64url-encoded, not encrypted, so anyone can read them. Never put passwords or secrets in a JWT payload.

What does 'exp' mean?

exp is the expiry time as a Unix timestamp. If the current time is past exp, the token is expired and a server should reject it. The decoder shows expiry in plain language.

Is my token sent to a server?

No. Splitting and Base64url-decoding happen entirely in your browser. The token is never uploaded, which matters because tokens can grant access to accounts.

MB
Mustafa Bilgic · Editor, Calcool
Follows the JWT structure defined in RFC 7519. Signature is not verified (never paste keys online). Everything runs in your browser — nothing you enter is uploaded, logged or stored.

Related calculators