ToolzyLabToolzyLab
Developer Tools · Practical guide

Reading JWTs Properly

A JWT looks like a sealed envelope but reads like a postcard. Knowing what each segment means — and what the signature does and does not protect — separates routine token inspection from security mistakes.

Updated 2026-08-06 · ~7 min read

The three segments, mechanically

A JWT is three base64url strings joined by dots: header, payload, signature. The header names the algorithm. The payload carries claims — key-value statements about a subject. The signature is computed over the first two segments with a key only the issuer holds. Decoding means base64url-decoding the first two segments; no key is needed, which is by design. The token is meant to be readable — its security rests on the signature, not on hiding the contents.

The claims that matter in daily work

Standard claims do most of the debugging work: sub identifies the user, exp and iat define the validity window, iss names the issuer, aud names the intended recipient. When authentication fails mysteriously, exp is the first thing to check — expired tokens are the most common cause of sudden logouts. Clock skew between client and server can reject technically valid tokens too, so compare exp against the server's clock, not just yours.

Why readable claims are never secrets

The most persistent JWT mistake is storing sensitive data in claims because the token 'looks encrypted.' Anyone who holds the token can decode the payload in seconds — the signature prevents tampering, not reading. Passwords, internal IDs you would not expose, and personal data belong server-side, referenced by a subject identifier at most. If a claim would be dangerous in a log file, it does not belong in a token.

Signature verification is a different job than decoding

Decoding answers 'what does this token say'; verification answers 'did the real issuer create it.' Verification requires the issuer's secret or public key and an algorithm check. A token you decoded locally tells you nothing about authenticity — a beautifully formatted token with a forged signature is worthless. Client-side tools inspect; only the server holding the key can trust.

The alg confusion attack, briefly

Historic JWT vulnerabilities came from servers trusting the header's alg field blindly — accepting alg: none, or treating an RSA public key as an HMAC secret. Modern libraries reject these by default, but the lesson generalizes: never let the token choose its own verification rules. When debugging, reading the header's alg is diagnostic; when implementing, pin the accepted algorithm in server configuration.

Debugging auth flows with a decoder

The standard workflow: reproduce the failure, decode the token the request actually carries, then check exp, iss, and aud against what the API expects. Mismatched audience claims catch cross-environment mixups — a staging token presented to production, for instance, which reads as valid until the aud check rejects it. Reading the token answers 'what did the client send' in seconds, which is half of every auth bug.

Refresh tokens and storage hygiene

Access tokens are short-lived by design; refresh tokens trade them for new ones. Storage choice follows from sensitivity: access tokens in memory survive XSS poorly but limit blast radius, while refresh tokens stored long-term need real protection. The decoder's role here is checking lifetimes — if your access token's exp is days out, the design is working against you.

Tokens beyond login

JWTs also carry state in payment webhooks, service-to-service calls, and signed URLs. The same reading discipline applies: identify which claims the consumer validates, decode, and compare. Payment providers document exactly which claims their signatures cover; webhook debugging is mostly decoding and matching against those docs.

Local decoding for live tokens

Production tokens contain user identifiers and session context you should not paste into arbitrary websites. Local decoding runs in your browser tab: the token is transformed in place and never transmitted. For inspecting live credentials — the everyday case — that locality is the difference between a safe habit and a leak vector.

Reading the issuer's discovery document alongside the token

Tokens make far more sense next to their issuer's metadata. OpenID Connect providers publish a discovery document listing supported algorithms, the signing-key endpoint, and claim conventions. The debugging sequence improves dramatically: decode the token, pull the discovery document, and compare — is the header's algorithm in the supported list? Does the issuer claim match the documented issuer exactly (trailing slashes matter)? Mismatches here explain a class of 'signature valid but token rejected' failures that pure token inspection never reveals.

Enterprise SSO failures that decode into obvious causes

Single-sign-on incidents repeatedly trace to a short list of claim problems visible in a decoded token: audience set to the wrong application ID after a re-registration, issuer changed when the identity provider's domain migrated, group claims exceeding size limits and silently dropping, and clock skew from virtualized servers drifting. Building this checklist turns SSO triage from escalation theater into claim inspection: decode, check aud, iss, exp, and group presence, compare against documented expectations. Most enterprise token issues resolve in that loop without touching the identity provider's team.

Token lifetime tuning: reading exp as design feedback

The exp claim encodes an architectural decision worth auditing. Access tokens living hours or days suggest refresh flows were skipped entirely — larger blast radius for any leaked token. Tokens expiring in minutes with no refresh mechanism explain user complaints about constant re-login. The balanced pattern most security guidance converges on: short-lived access tokens (minutes), longer-lived refresh tokens held more carefully, and silent renewal keeping users logged in. Decoding what your own applications issue is the fastest way to see which pattern you actually run versus which one you intended.

JWT rule: decode to inspect, verify to trust — and keep anything sensitive out of claims, because the payload is readable by design.

Decoding tokens safely and correctly

The single most important fact about JWTs: the header and payload are Base64URL-encoded, not encrypted. Anyone who holds the token can read every claim — user ids, email addresses, roles, tenant identifiers — exactly as this tool displays them. That has two consequences. First, never put sensitive data in claims; the signature prevents tampering, not reading. Second, treat tokens in logs, bug reports, and screenshots as live credentials, because they are: a JWT is bearer proof, and a leaked access token is an account session until it expires.

When a token fails validation, the decoder tells you where to look. A signature error usually means the wrong secret or algorithm — check that the header's alg matches what your verifier expects; the classic attack is an alg: none token or an RS/HS confusion, and any serious verifier rejects both. An expiry failure is legible directly from the exp claim: convert it from epoch seconds and compare to the clock. Skew of a few seconds between systems is normal, which is why validators accept a leeway.

Claim reading is the everyday use. The standard fields — iss, sub, aud, exp, iat — answer who issued it, whom it identifies, who may accept it, and whether it is current. Custom claims sit alongside them, and decoding a production token is the fastest way to confirm your backend is actually emitting the claim your frontend depends on, rather than trusting the code path.

Common mistakes with this tool

  • Storing secrets in claims because the encoded string looks opaque.
  • Checking only the signature and ignoring expired or wrong-audience claims.
  • Trusting the header's alg field during verification.
  • Pasting production tokens into server-side decoder websites.

Frequently asked questions

Is decoding a JWT the same as verifying it?

No — decoding reads the payload; verifying checks the signature with the issuer's key. Only verification proves authenticity.

Can I change a claim and re-sign?

Not without the issuer's key — the signature covers the payload, and tampering invalidates it.

Why is my valid token rejected?

Usually exp passed, aud mismatches the API, or clock skew. Decode and compare each claim to the API's expectations.

Are JWT payloads encrypted?

No — they are base64url-encoded, trivially readable. JWE exists for encryption but is rarely what standard JWTs use.

Is it safe to decode my session token here?

Yes — decoding is fully local; the token string never leaves your browser.

Is it safe to decode a real token online?

With a local, in-browser decoder yes — the token never leaves your machine. Avoid services that send tokens to a server: a leaked bearer token is a working credential until expiry.

Why does my token say 'invalid signature' even though it decodes?

Decoding needs no key; verifying does. The mismatch means wrong secret, wrong algorithm, or a tampered token. Check the header's alg against your verifier's expectation.

Privacy note: Decoding runs in your browser; tokens never upload.
Next step: open the JWT Decoder and try this workflow on a sample before you use it on important files.