yigityalim
projectshandbookslabshireshare
xgithub
siteprojectshandbookslabschangelog
aboutusesnowhireshare
elsewherexgithublinkedinemail
metarssllms.txtsitemap
© 2026 Yiğit Yalım. All rights reserved.
/
Back to Labs
May 10, 2026·auth

JWT Decoder + Verifier

Paste a JSON Web Token, split into header / payload / signature, verify with an HMAC secret. Auto-flags expired, not-yet-valid, and dangerous "alg none" tokens.

jwt · jose · hmac · hs256

PreviousJSON FormatterNextJWT Generator

A JWT (JSON Web Token) is header.payload.signature joined by dots, base64url-encoded, optionally signed. Understanding what each part holds and what the signature buys you covers ~80% of modern auth.

This lab takes a pasted token, splits it into three parts, base64url-decodes them, parses the JSON. Paste an HMAC-SHA256 secret and it verifies the signature client-side. exp, nbf, iat claims become human-readable timestamps; expired tokens are flagged red. The dangerous alg: "none" case is highlighted with a security banner.

JwtDecoder — decode + verify, all in browser
jwt token
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IllpxJ9pdCBZYWzEsW0iLCJpYXQiOjE3Nzg2OTU1MzMsImV4cCI6MTc3ODY5OTEzM30.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
header
36 chars
{
  "alg": "HS256",
  "typ": "JWT"
}
payload
103 chars
{
  "sub": "1234567890",
  "name": "Yiğit Yalım",
  "iat": 1778695533,
  "exp": 1778699133
}
time-based claims
valid · expires in 1h
exp
17786991332026-05-13 19:05:33 UTC+00:00
iat
17786955332026-05-13 18:05:33 UTC+00:00
signature verify · HS256

The three parts

A JWT is the dot-joined concatenation of:

  1. Header (red) — algorithm + token type:
    { "alg": "HS256", "typ": "JWT" }
  2. Payload (violet) — claims. sub (subject), iat (issued at), exp (expires at) are the most common:
    { "sub": "user-123", "iat": 1745731600, "exp": 1745735200 }
  3. Signature (sky) — HMAC(secret, base64url(header) + "." + base64url(payload)). Or RSA/ECDSA. To verify it you need the matching secret or public key.

Never trust without verifying

Three places where it goes wrong:

  1. Accepting alg: "none" — some libraries (including old jsonwebtoken v0.x) accepted this algorithm; an attacker could forge unsigned tokens. Modern libraries reject it but you should still pass verify({ algorithms: ["HS256"] }) as an explicit allowlist.

  2. Algorithm confusion — server expects RS256 (asymmetric) but an attacker submits a token signed with the public key as if it were an HMAC secret, switching to HS256. Again: explicit algorithms allowlist defeats this.

  3. Decoding without verifying — jwt.decode() (not verify) only base64url-decodes, never checks the signature. Never use decode-only in production; always jwt.verify(token, secret, options).

exp vs nbf vs iat

ClaimMeaningServer check
iatIssued atLogging only — must not be in the future
nbfNot beforeReject if now < nbf
expExpires atReject if now >= exp

Allowing ±60-300 seconds of clock skew is common practice. More than an hour of tolerance opens auth-bypass risk.

Token storage

  • HttpOnly + Secure + SameSite=Strict cookie — the secure default
  • Not localStorage / sessionStorage — XSS exfiltrates them
  • Web Worker memory works too, but it's complex