toooly-box

JWT Decoder

Paste a token and read what is inside it: the header, the claims, and whether it has expired.

runs locally
JWT decoder
Paste the token
Expired
IssuedNov 14, 2023, 10:13 PM
ExpiresNov 14, 2023, 11:13 PM
Header
Payload (claims)
Signature

Shown, never checked: verifying it needs the signing key, which belongs on a server.

S2V5SXNOb3RDaGVja2VkSGVyZQ

What is a JWT?

A JWT, or JSON Web Token, is three Base64url pieces joined by dots: a header, a payload of claims, and a signature. The first two are readable by anyone who holds the token; only the signature proves it was not altered. A JWT is signed, not encrypted.

How it works

A JWT is three parts separated by dots: a header, a payload and a signature. The first two are base64url-encoded JSON, so decoding them is a matter of reversing the encoding and parsing the result: no key, no network, no secret involved.

The decoder resolves the registered date claims as it goes. exp, iat and nbf are seconds since the epoch, which is unreadable at a glance, so they are shown as dates and exp is compared against your clock to say whether the token is still live.

The signature is displayed and left alone. Verifying it requires the signing key, and a key that reaches a browser tab is a key that has leaked, so that check belongs on a server, not here.

What is inside a JSON Web Token

A JWT (RFC 7519) is a signed statement that some issuer makes about some subject, encoded so it survives a URL or an HTTP header. The three dot-separated parts each do one job.

  • The header names the algorithm and the type: {"alg":"HS256","typ":"JWT"}. It may also carry kid, the key id, which tells the verifier which of several public keys to check against.
  • The payload the claims. Registered ones have agreed meanings: iss (issuer), sub (subject, usually the user id), aud (audience), exp (expiry), iat (issued at), nbf (not before), jti (a unique id). Everything else is whatever the issuer chose to put there: roles, a tenant, an email.
  • The signature the first two parts signed with the key. It is what makes the token trustworthy, and it is the one part this tool deliberately does not touch.

Decoding is not verifying

This is the distinction that matters, and the one that causes real security incidents. Decoding a JWT reads it. Verifying a JWT proves that the issuer actually signed it and that nobody changed a claim on the way. They are different operations, and only the second one makes the contents trustworthy.

Anyone holding a token can decode it: that is what you are doing on this page. So a JWT payload is not a place to put anything you would not want read: it is signed, not encrypted. If the claims need to be unreadable to the bearer, you want JWE, or an opaque token whose meaning lives only in your own database.

And never let an unverified token decide anything. The classic attack is the "alg": "none" token, where an attacker strips the signature and rewrites the claims; a server that decodes without verifying accepts it as an administrator. A library that verifies should be told which algorithms it may accept, rather than trusting the header to pick.

Answering the questions you actually came with

  • "Is this token expired?" exp is shown as a date and compared against your clock. Remember the clock is yours: a few seconds of skew between your machine and the server is normal, and most libraries allow a small leeway for exactly this reason.
  • "Which account is this?" sub is the subject, the stable identifier. The display name beside it, if there is one, is a convenience and can change; sub should not.
  • "Why is the gateway rejecting it?" check aud against what the API expects, iss against the issuer it trusts, and nbf, which makes a token invalid until a moment that may not have arrived yet.
  • "Which key signed it?" the kid in the header, matched against the keys published at the issuer’s JWKS endpoint. A rotated key with a stale cache is a common cause of sudden mass rejection.

When a token will not decode

  • It is not three parts count the dots: a JWT has exactly two. One dot usually means the signature was trimmed; four means two tokens were pasted together.
  • A character outside the Base64 alphabet almost always a truncated copy that picked up a quote, a comma or a trailing ellipsis from the surrounding text. Check both ends of the string first.
  • It decodes but is not JSON then it is probably not a JWT at all. Opaque session tokens and API keys are often Base64 too, and carry no readable structure: their meaning lives in the issuer’s database.
  • A Bearer prefix copied straight from an Authorization header. It is stripped here automatically, but a library that is handed the whole header value will not do that for you.

Questions people ask

Does this verify the signature?

No, and that is deliberate. Verification needs the signing key, and a key that reaches a browser is a leaked key. The signature is shown so you can see it is there; checking it belongs on your server.

Is my token uploaded?

No. The decode runs in your browser and nothing is sent anywhere: the tool keeps working offline. Still, treat any token you paste anywhere as one worth rotating.

Why can anyone read my JWT payload?

Because a JWT is signed, not encrypted: base64url is an encoding anyone can reverse. Never put anything secret in the claims; use JWE or an opaque token if the contents must be unreadable.

What does "alg": "none" mean?

An unsigned token. It is a legitimate part of the spec and a well-known attack: a server that decodes without verifying will accept rewritten claims. Always tell your library which algorithms it may accept.

My token looks expired but the API accepts it

exp is compared against your own clock. A small difference between your machine and the server is normal, and most libraries allow a few seconds of leeway on purpose.