How JWT Works
JSON Web Tokens (JWT) are a compact, URL-safe way to represent claims between parties. This guide covers structure, algorithms, and security best practices.
JWT Structure (Header.Payload.Signature)
Header
Specifies the signing algorithm and token type
{"alg":"HS256","typ":"JWT"}Payload
Contains claims (user data and metadata)
{"sub":"1234567890","name":"John Doe","iat":1516239022}Signature
Verifies the token hasn't been tampered with
HMACSHA256(base64(header) + '.' + base64(payload), secret)
How JWT Authentication Works
Standard Claims (RFC 7519)
| Claim | Name | Description |
|---|---|---|
| iss | Issuer | Who issued the token (e.g., auth server URL) |
| sub | Subject | Who the token is about (usually user ID) |
| aud | Audience | Who should accept the token (e.g., API URL) |
| exp | Expiration | Unix timestamp when token expires |
| nbf | Not Before | Token not valid before this time |
| iat | Issued At | When the token was created |
| jti | JWT ID | Unique identifier for the token |
Signing Algorithms
HMAC with SHA-256. Same secret for signing and verification.
Use case: Single server, monolithic apps
RSA signature with SHA-256. Private key signs, public key verifies.
Use case: Microservices, third-party integration
ECDSA with P-256 curve. Smaller keys, same security as RSA.
Use case: Mobile apps, IoT, modern systems
No signature. Anyone can forge tokens.
Use case: NEVER use in production
Security Best Practices
Never trust a JWT without verifying its signature. Reject 'alg: none'.
Always verify 'exp' claim. Use short expiration times (15-60 minutes).
Check 'iss' and 'aud' claims match expected values to prevent token reuse attacks.
JWTs are often in headers/cookies. Always use TLS to prevent interception.
Use HttpOnly cookies or secure storage. Avoid localStorage for sensitive tokens.
Don't store sensitive data in JWT. It's Base64 encoded, not encrypted.
Common Vulnerabilities
Attacker changes RS256 to HS256 and signs with public key (known)
Fix: Always specify expected algorithm, reject 'none'
JWTs logged, exposed in URLs, or stored insecurely
Fix: Use short expiration, HttpOnly cookies, never log tokens
Same key used for different purposes allows token reuse
Fix: Use unique keys per service, validate 'aud' claim
JWT vs. Server Sessions
JWT (Stateless)
- ✅ No server storage needed
- ✅ Scales horizontally easily
- ✅ Works across services
- ❌ Can't revoke instantly
- ❌ Larger than session ID
Sessions (Stateful)
- ✅ Instant revocation
- ✅ Small session ID
- ✅ Sensitive data on server
- ❌ Requires session store
- ❌ Harder to scale