utilyfe

JWT Decoder

Read a token's claims, see whether it has expired, and check an HS256 signature without sending it anywhere.

Runs entirely in your browser. Nothing you enter is uploaded or stored.

How to use the JWT Decoder

  1. 1Paste the token into the box. A "Bearer " prefix is fine; it's ignored.
  2. 2Read the status line for whether the token has expired, and the claims table for what it carries.
  3. 3The header and payload appear as formatted JSON underneath.
  4. 4For an HS256, HS384 or HS512 token, enter the shared secret and press Check to test the signature.

What’s actually inside a JWT

A JWT is three pieces of Base64url text joined by dots:

header.payload.signature

  • Header: the algorithm used to sign, usually HS256 or RS256, and the type.
  • Payload: the claims (who the token is about, who issued it, when it expires) plus whatever the application adds, like roles or a tenant id.
  • Signature: the proof, made over header.payload with a key.

Base64url is not encryption. The first two parts are readable by anyone who has the token, which is why a JWT should never carry a password, a card number or anything you wouldn’t put in a log.

Decoding is not verifying

Reading a token tells you what it claims. It tells you nothing about whether those claims are true.

Anyone can take a token, change "role": "user" to "role": "admin", and re-encode it. What stops that from working is the signature: the server recomputes it with its key and rejects the token when it doesn’t match. So:

  • Decoding (what this page does by default) needs no key and proves nothing.
  • Verifying needs the key, and is the only thing that makes the claims trustworthy.

Both matter in different moments. When debugging, you usually want to read the claims. When something is being rejected, you want to know whether the signature matches.

The claims you’ll see most

Claim Name What it means
iss Issuer Who created the token
sub Subject Who or what it’s about, often a user id
aud Audience Which service is meant to accept it
exp Expires After this moment the token is dead
nbf Not before Not valid until this moment
iat Issued at When it was created
jti Token ID A unique id, used to revoke or de-duplicate

The three time claims are counted in seconds since 1970, which is why they look like meaningless numbers in other tools. Here they’re shown as a date plus plain English (“expires in 12 minutes”, “issued 3 days ago”) because that’s usually the thing you’re actually checking.

The alg: none trap

The specification allows a token to declare that it has no signature at all. If a library trusts the header and skips the check, anyone can mint an admin token by hand.

When a token here says alg: "none", the page says so in red. The defence on the server is simple: decide which algorithm you accept before you look at the token, and never let the token choose.

A related trap is algorithm confusion, where an RS256 token is re-signed as HS256 using the public key as the shared secret. The same rule prevents it: pin the expected algorithm.

Checking an HS256 signature here

Enter the shared secret and press Check. Your browser computes the HMAC over header.payload and compares it with the signature, using the Web Crypto API that’s already built in. Three answers are possible:

  • Signature matches this secret: the token is intact and was signed with that key.
  • Signature does not match: the token was altered, or it was signed with a different key.
  • Only HS256, HS384 and HS512 can be checked here: the token uses a public-key algorithm, which needs the issuer’s public key.

None of this leaves the tab. That’s worth caring about: a token pasted into a random website is a credential handed to a stranger, and the same goes for the secret.

Questions

Is my token sent to a server?
No, and this is the point of the page. Decoding, the claim dates and the signature check all run in this browser tab using its built-in crypto. You can prove it: open your browser's network tools, or turn off your wi-fi, and the page keeps working. A token is a live credential, so where you paste it matters.
Does decoding a token mean it's valid?
No. The header and payload are only Base64url-encoded, so anyone holding the token can read them, and anyone can edit them. Only the signature proves the token came from the issuer and hasn't been altered, which is why it has to be checked with a key.
Can it verify RS256 or ES256 tokens?
Not yet. Those are signed with a private key and verified with the issuer's public key, so you'd need to paste the public key or fetch the issuer's JWKS. Today this page checks the HMAC family (HS256, HS384, HS512), where one shared secret does both jobs.
Is it safe to type a secret in here?
The secret stays in the page: it's passed to your browser's crypto and never transmitted. Even so, treat production secrets carefully: use a test secret where you can, and never paste one into a tool whose behaviour you can't check.
It says expired, but my app still accepts the token. Why?
Expiry is compared against your computer's clock. If that clock is wrong, or the server allows a little leeway for clock differences (most do, usually 30 to 60 seconds), the two answers can differ near the boundary. The dates shown here are in UTC.