JWT Tokens Explained: How Modern Authentication Works

JSON Web Tokens are everywhere — but how do they actually work? A clear explanation of JWT structure, signing, and security best practices.

JWT Tokens Explained: How Modern Authentication Works

What is a JWT?

A JSON Web Token (JWT, pronounced "jot") is a compact, URL-safe way to transmit claims between two parties. JWTs are the backbone of modern stateless authentication — instead of storing sessions on the server, the session data travels with the user in a signed token.

Anatomy of a JWT

A JWT has three parts, separated by dots:

xxxxx.yyyyy.zzzzz
 │     │     └── Signature
 │     └────────── Payload (claims)
 └───────────────── Header

The Three Components

// 1. Header (base64url encoded JSON)
{
  "alg": "HS256",   // Algorithm
  "typ": "JWT"
}

// 2. Payload (base64url encoded JSON)
{
  "sub": "1234567890",   // Subject (user ID)
  "name": "Sarah Chen",
  "role": "admin",
  "iat": 1716000000,     // Issued at
  "exp": 1716086400      // Expiration
}

// 3. Signature
HMACSHA256(
  base64UrlEncode(header) + "." + base64UrlEncode(payload),
  secret
)

How It Works (Auth Flow)

  1. User logs in with username + password
  2. Server validates credentials, generates a JWT
  3. Server returns the JWT to the client
  4. Client stores the JWT (localStorage or httpOnly cookie)
  5. Client sends JWT in Authorization: Bearer <token> header
  6. Server verifies signature — if valid, request proceeds

Common Algorithms

  • HS256 — HMAC with SHA-256 (symmetric, shared secret)
  • RS256 — RSA with SHA-256 (asymmetric, public/private key)
  • ES256 — ECDSA with SHA-256 (modern, efficient)

Security Best Practices

  • Always validate signatures — never trust a token without verification
  • Set short expiration times — 15–60 minutes for access tokens
  • Use refresh tokens — rotate access tokens without re-login
  • Store secrets securely — environment variables, not in code
  • Prefer httpOnly cookies — not localStorage (XSS vulnerable)
  • Include jti — unique token ID for revocation

Never Do These

  • Don't put sensitive data in the payload (it's just base64-encoded, not encrypted)
  • Don't use none algorithm (JWT algorithm confusion attacks)
  • Don't skip signature verification
  • Don't store JWTs in localStorage if you can avoid it

Validate JWTs in Code

// Node.js with jsonwebtoken
const jwt = require('jsonwebtoken');

const decoded = jwt.verify(token, process.env.JWT_SECRET);
console.log(decoded.userId, decoded.role);

Frequently Asked Questions

JWT vs session cookies — which should I use?

JWT is best for stateless APIs, microservices, and SPAs that need to call multiple services without a shared session store. Session cookies are simpler for traditional server-rendered apps, allow immediate server-side revocation, and have built-in CSRF protection. For most web apps, httpOnly session cookies are safer; reach for JWT when you genuinely need statelessness.

Where should I store JWTs on the client?

Best: httpOnly + Secure + SameSite=Strict cookie — immune to XSS theft but needs CSRF protection. Acceptable: in-memory (lost on refresh, no XSS risk but bad UX). Avoid: localStorage — any XSS vulnerability lets attackers steal the token and all your user's data. The httpOnly cookie approach is the industry standard for sensitive apps.

How do I revoke a JWT before it expires?

JWTs can't be truly revoked without checking the server (defeating statelessness). Three workarounds: (1) Short expiration (15 min) + refresh tokens you can revoke, (2) Maintain a server-side 'revoked jti' list checked on every request, (3) Use a token versioning system where the user's current version is stored server-side. For most apps, short expiration + refresh tokens is the right answer.

← Back to Blog
Copied!