IQ
PayloadIQ
← PayloadIQ Guides

Decoding JWTs Safely

You can read a JWT in seconds without any library. What you cannot do in the browser is trust it. Here is the line between the two.

A JSON Web Token looks cryptic, but it is mostly just JSON in disguise. It has three parts separated by dots — header.payload.signature — and the first two are base64url-encoded JSON you can read instantly. Decoding one is not breaking anything: tokens are encoded for transport, not encrypted for secrecy.

What is inside

A typical token decodes to a header and a payload:

// header
{ "alg": "HS256", "typ": "JWT" }

// payload (the "claims")
{
  "sub": "1042",
  "role": "admin",
  "iat": 1717286400,
  "exp": 1717290000
}

The header names the signing algorithm. The payload carries claims: sub (the subject, usually a user id), plus standard time claims iat (issued-at) and exp (expiry), both as Unix seconds. To check whether a token is expired, compare exp against the current epoch: Date.now() / 1000 > exp.

The part that matters: the signature

The third segment is a signature computed over the header and payload using a secret (HMAC) or a private key (RSA/ECDSA). It is the only part that proves the token is genuine. Anyone can craft a token with role: "admin" in the payload — what they cannot do is produce a valid signature without the key.

This is why you never trust a JWT decoded in the browser. Reading the payload tells you what the token claims; only verifying the signature on the server, with the key, tells you whether those claims are real. Decode client-side to debug and display; authorize server-side after verification, every time.

Two traps to know

The alg: "none" attack: some libraries once accepted a token that declared no algorithm and skipped verification entirely. Always pin the expected algorithm on the server. The related algorithm confusion attack swaps an RS256 token for an HS256 one so the public key gets used as an HMAC secret — again, fixed by pinning the algorithm rather than trusting the header.

When to use a decoder

Pop a token into a decoder when you're debugging an auth flow, checking why a session expired, confirming which claims your identity provider issues, or inspecting scopes. The JWT Decoder does this entirely in your browser, shows issued-at and expiry status, and never sends the token anywhere — which matters, because a live access token is a credential.

Common mistakes

  • Authorizing on decoded claims. Reading role: "admin" in the browser and trusting it is the classic JWT vulnerability.
  • Verifying signatures client-side. The secret would have to ship to the browser, which defeats the entire scheme.
  • Pasting live tokens into random sites. A server-side decoder receives a working credential. Use a local tool.
  • Logging full tokens. They land in log aggregators and stay valid until they expire. Log the sub, not the token.
  • Ignoring exp. A decoded token can be long expired; always check the claim before relying on it.

Decoding a JWT is a five-second read. Trusting one is a server-side decision. Keep those two ideas separate and JWTs stop being mysterious.

Open the JWT Decoder

Related guides

Browser-local JSON ToolsJSON Formatter & Validator