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.
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)
- User logs in with username + password
- Server validates credentials, generates a JWT
- Server returns the JWT to the client
- Client stores the JWT (localStorage or httpOnly cookie)
- Client sends JWT in
Authorization: Bearer <token>header - 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
nonealgorithm (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);