Home/Blogs/HomeBlogJWT Decoder Guide 2026

JWT Tokens Explained — How to Decode, Verify and Debug JWTs in 2026

·12 min read

A complete guide to JSON Web Tokens — what the three parts actually contain, how HS256 vs RS256 vs ES256 differ, what exp/iat/sub claims mean, and how to use a free browser-based JWT decoder, verifier, and builder.

If you've spent any time building web APIs, you've probably pasted a JWT into a decoder at least once — usually right after getting a 401 Unauthorized error that made no sense, or trying to figure out why a token your backend issued isn't being accepted by a downstream service.

JWTs are everywhere. Every major auth system — Auth0, Firebase Auth, Supabase, AWS Cognito, Keycloak, Google OAuth — issues them. REST APIs use them as Bearer tokens. WebSocket connections authenticate with them. And yet the format confuses developers at every experience level, because the token looks like encrypted nonsense until you know the pattern.

This guide covers everything: what the three parts actually contain, what each standard claim means, how the signature algorithms work, how to debug common JWT errors, and how to use the free browser-based JWT decoder, verifier, and builder.

What a JWT Actually Is

JWT stands for JSON Web Token. It's a compact, URL-safe string that encodes a JSON object along with a cryptographic signature. The full spec is RFC 7519, but the practical summary is: a JWT lets a server send structured data to a client (or another server) in a format that can be verified without any database lookup.

The defining characteristic is the three dots. Every JWT has exactly two periods separating three Base64URL-encoded segments:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyXzEyMzQ1IiwibmFtZSI6IkpvaG4gRG9lIiwiZXhwIjoxNzY5NTM2MDAwfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
  • Red — Header: algorithm and token type
  • Blue — Payload: the actual claims (user ID, roles, timestamps)
  • Green — Signature: cryptographic proof the token was not tampered with

The crucial thing to understand: Base64URL encoding is not encryption. Anyone who has a JWT can decode the header and payload without any key. The signature only proves the token was created by someone with the signing key and has not been modified since. It does not hide the contents.

Part 1 — The Header

Decode the first segment and you get a small JSON object. Almost always:

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

The alg field declares which algorithm was used to sign the token. This is critical for verification — you must use the same algorithm to verify as was used to sign. Some tokens include a kid (Key ID) field — a hint about which specific key from a JWKS endpoint was used, allowing auth servers to rotate keys without breaking existing tokens.

Part 2 — The Payload and Standard Claims

The payload is where the useful data lives. RFC 7519 defines registered claim names — standard fields with well-known meanings:

Claim Full Name Type What It Means
iss Issuer string/URI The server that issued the token
sub Subject string Who the token is about — typically a user ID
aud Audience string/array The service(s) this token is intended for
exp Expiration Time Unix timestamp Token must be rejected after this time
nbf Not Before Unix timestamp Token must be rejected before this time
iat Issued At Unix timestamp When the token was created
jti JWT ID string Unique ID to prevent replay attacks

Why Timestamp Claims Cause Most 401 Errors

The exp, iat, and nbf claims are stored as Unix timestamps — seconds since January 1, 1970. A raw value of 1769536000 is meaningless at a glance. The JWT decoder converts these to readable dates and shows a status badge — Expired, Valid, or Not Yet Active.

The most common cause of JWT debugging sessions is a token that was valid when the developer tested it, but by the time a colleague checked the logs, the token had expired. Seeing the actual expiry date instantly resolves this without any mental arithmetic.

Part 3 — The Signature

The signature is computed over the first two parts of the JWT (Base64URL(header) + "." + Base64URL(payload)). Any change to either part — even a single character — produces a completely different signature. This prevents tampering.

What the signature does NOT do: it does not hide the header or payload. Anyone with the token can read the payload. It only proves that whoever produced the signature had the correct key at signing time. This is why you should never store sensitive data — passwords, full PII, private keys — in a JWT payload.

JWT Algorithms — HS256, RS256, ES256 and the Rest

Algorithm Family Key Type Best For
HS256 / HS384 / HS512 HMAC Shared secret Single-server apps, internal services
RS256 / RS384 / RS512 RSA Private + Public key pair Multi-service, OIDC providers
ES256 / ES384 / ES512 ECDSA EC Private + Public key Performance-sensitive, smaller signatures
PS256 / PS384 / PS512 RSA-PSS Private + Public key pair FIPS/compliance environments
none No key Never use in production

HS256 vs RS256 — The Key Architectural Choice

With HS256, a single shared secret is used for both signing and verification. Any service that can verify a token can also create one. This is fine for a single backend, but in a microservices architecture it means every service that needs to verify tokens also has the signing key — a significant security surface area if any service is compromised.

With RS256, the auth server signs tokens with a private key. Every other service verifies with the corresponding public key, which can be distributed freely — often published at a JWKS endpoint like https://auth.example.com/.well-known/jwks.json. A compromised downstream service can read tokens but cannot forge them. This is why RS256 is the standard for Auth0, Firebase, Cognito, and all major OIDC providers.

ES256 (ECDSA) is the modern alternative to RS256 — same asymmetric benefits but much smaller signatures (64 bytes vs 256 bytes) and faster computation. If you're building a new system and performance or bandwidth matters, ES256 is worth evaluating.

The alg:none Attack — Unsigned Tokens Are Not Safe

In 2015, researchers discovered that many JWT libraries would accept tokens with alg: "none" and no signature as valid. The attack is straightforward: take any valid token, change the header's alg to "none", modify the payload (grant admin role, change user ID, extend expiry), strip the signature entirely, and re-encode. A vulnerable server accepts the forged token.

The fix is simple but must be explicit: always specify allowed algorithms in your validation code. In Node.js jsonwebtoken: jwt.verify(token, secret, { algorithms: ['HS256'] }). Never rely on a library to make the right default choice — explicitly reject algorithms you don't use.

Using the JWT Tool — Three Tabs Explained

Tab 1 — Decode

Paste any JWT from an Authorization header, browser DevTools, an API response, or a log file. The decoded output appears instantly, showing: the algorithm with a plain-English description, every payload claim labeled for the 25+ known standard and OIDC claims, timestamp claims converted to readable dates with a validity status badge (Expired / Valid / Not Yet Active), and the raw JSON copyable with one click.

Use this tab for: debugging auth errors, verifying what claims an OIDC provider is sending, checking token expiry without manually converting Unix timestamps.

Tab 2 — Verify Signature

Switch to Verify after decoding to cryptographically confirm the signature. For HMAC tokens, paste your shared secret. For RSA or ECDSA tokens, paste the PEM-formatted public key. Verification uses the browser's native Web Crypto API — no data is sent to any server. The result shows either Valid Signature or Invalid Signature clearly.

Use this tab for: confirming a token was signed by the expected key, catching configuration mismatches (wrong secret, wrong key) during development, and validating tokens from third-party OIDC providers.

Tab 3 — Build a JWT

Select an algorithm (HS256, HS384, or HS512), enter your HMAC secret, add claims using preset buttons (sub, iss, aud, email, roles) or custom key-value pairs, set an expiry duration, and click Build Token. The generated JWT appears immediately for copying into Postman, curl, or a test suite.

Use this tab for: generating test tokens without writing sign() code, verifying your validation logic correctly handles specific claim combinations, and creating sample tokens for API documentation or demos.

Debugging JWT Auth Errors — Six Steps

When a 401 Unauthorized hits and you're not sure why, follow this sequence:

  • Step 1: Extract the token from the Authorization header (Bearer <token>) or cookie.
  • Step 2: Paste into the decoder. Check exp — is it in the past? Expired token is the most common cause.
  • Step 3: Check aud — does the audience match what your server expects? A token issued for api.example.com will fail validation on app.example.com.
  • Step 4: Check iss — does the issuer match your auth server's configured issuer? A trailing slash mismatch (https://auth.example.com vs https://auth.example.com/) will fail strict issuer validation.
  • Step 5: Check the alg in the header — is it what your server's validation config expects?
  • Step 6: Use the Verify tab with your secret or public key to confirm the signature is intact and matches the key you expect.

JWT vs Session Cookie

Factor JWT Session Cookie
State Stateless — no DB lookup Stateful — server stores session data
Horizontal scaling Easy — any server can verify Requires shared session store (Redis)
Instant revocation Hard — needs a token blocklist Easy — delete from store
XSS risk High if stored in localStorage Low with HttpOnly cookie
Cross-domain use Easy — Authorization header Requires CORS + SameSite config

JWT Security Checklist

  • Always specify allowed algorithms. Never let the library decide based on the alg header value — that is the alg:none attack vector.
  • Keep access token expiry short. 15–60 minutes is standard. Use refresh tokens for longer sessions.
  • Use RS256 or ES256 in multi-service architectures. Distributing your HMAC signing secret to every microservice is a security risk.
  • Never store sensitive data in the payload. Passwords, full PII, and secrets are readable by anyone with the token.
  • Store in HttpOnly cookies, not localStorage. localStorage is XSS-accessible. HttpOnly cookies are not.
  • Validate all relevant claims. Check exp, iss, and aud — not just the signature.
  • Use a token blocklist for logout. JWTs cannot be invalidated mid-lifetime without one.

Final Thoughts

JWTs look complicated at first glance — three segments of Base64 text that seem like gibberish. But the structure is simple and consistent: the header tells you the algorithm, the payload carries the claims, and the signature proves nothing was changed. Once that pattern is clear, every JWT you encounter becomes immediately readable.

The nuances — which algorithm to choose for which architecture, what exp and aud and iss mean and why, the alg:none vulnerability, the localStorage vs cookie tradeoff — are what separate developers who work with JWTs confidently from developers who spend hours tracing auth bugs.

The free JWT decoder, verifier, and builder handles the mechanical work: paste a token and see everything decoded with labels and expiry status; verify a signature against your secret or public key; build a test token for Postman without writing a line of code. Everything runs in your browser — no data is sent anywhere. That's the right tool for working with JWTs in 2026.

Frequently Asked Questions

What is a JWT token and what are its three parts?

A JWT (JSON Web Token) is a compact, self-contained string used to securely transmit information between parties. It consists of three Base64URL-encoded parts separated by dots: the Header (algorithm and token type), the Payload (claims about the user and the token), and the Signature (a cryptographic hash that proves the token has not been tampered with).

Is it safe to decode a JWT token online?

Yes, if the tool decodes entirely in your browser without sending the token to any server. The JWT payload is Base64URL-encoded, not encrypted, so decoding is a client-side operation. A properly built browser-based decoder uses JavaScript to decode the token locally. You can verify this by opening DevTools Network tab and confirming no requests are made when you paste and decode a token.

What is the difference between HS256 and RS256 in JWTs?

HS256 uses HMAC-SHA256 with a single shared secret — both the issuer and every verifier must know the same secret. RS256 uses RSA with a private key for signing and a public key for verifying. The private key stays only on the auth server while the public key can be distributed freely. RS256 is preferred in multi-service architectures where you want services to verify but not issue tokens.

What do the JWT claims exp, iat, and nbf mean?

exp (Expiration Time) is a Unix timestamp after which the token must be rejected. iat (Issued At) is the Unix timestamp recording when the token was created. nbf (Not Before) is a Unix timestamp before which the token must not be accepted. All three are standard registered claims defined in RFC 7519. A JWT decoder converts these Unix timestamps to human-readable dates and shows whether the token is valid, expired, or not yet active.

What does the JWT sub claim contain?

The sub (Subject) claim identifies the principal that is the subject of the JWT — typically a unique user identifier like a user ID or UUID. It is meant to be unique within the issuer's context and stable — it should not change even if the user updates their email or username. In OAuth 2.0 and OIDC flows, sub is the primary identifier for the authenticated user.

Can I verify a JWT signature without a backend?

Yes. Modern browsers support the Web Crypto API which can verify cryptographic signatures client-side. For HMAC tokens (HS256/384/512), paste the shared secret and the tool verifies locally. For RSA and ECDSA tokens (RS256, RS384, ES256, etc.), paste the PEM public key and the browser performs the asymmetric verification without sending any data to a server.

Why is alg:none in JWT dangerous?

A JWT with alg:none has no signature and is unsigned. Some JWT libraries would accept these tokens as valid if not explicitly configured to reject them. An attacker can modify the payload, set alg to none, strip the signature, and re-encode — and a vulnerable server would accept it. Always explicitly specify allowed algorithms in your JWT validation library and never accept alg:none tokens in production.

What is the difference between JWT and a session cookie?

Session cookies store only a session ID — the server looks up session data from a database on every request. JWTs store actual claims in the token itself — the server verifies the signature without any database lookup, making it stateless. JWTs scale better across multiple servers but cannot be instantly invalidated without a blocklist. Session cookies require shared state but can be revoked immediately by deleting the session.

Should I store a JWT in localStorage or a cookie?

HttpOnly cookies are safer than localStorage for storing JWTs. localStorage is accessible to JavaScript, meaning an XSS attack can steal tokens stored there. HttpOnly cookies cannot be accessed by JavaScript — only sent automatically by the browser with requests. For most web apps, HttpOnly Secure SameSite=Strict cookies are the recommended storage mechanism for JWTs.

How do I debug a JWT authentication error?

Decode the token and check: (1) Is exp in the past? Token is expired. (2) Does aud match what your server expects? (3) Does iss match your auth server's issuer URL? (4) Is the algorithm what your server accepts? (5) Use the Verify tab with your secret or public key to confirm the signature. These steps catch approximately 95% of JWT authentication bugs.

What are OIDC claims in a JWT?

OIDC (OpenID Connect) extends OAuth 2.0 with an ID Token containing standard identity claims: name, given_name, family_name, email, email_verified, picture (profile photo URL), preferred_username, locale, and azp (authorized party). When you sign in with Google, GitHub, or Auth0, the ID token you receive is a JWT containing these claims about the authenticated user.

How do I build a JWT for testing without writing code?

Use the JWT builder tab in the online tool. Select HS256/384/512, enter your HMAC secret, add standard claims using preset buttons or custom key-value pairs, set an expiry, and click Build Token. The generated JWT appears instantly for copying directly into Postman, curl, or your test environment. No sign() code required.

Sponsored

Sponsored banner