JWT structure
A JWT is three Base64URL-encoded parts separated by dots: header.payload.signature. The signature is computed with a secret (HMAC) or private key (RSA/ECDSA). The server validates the signature — no DB lookup needed.
Access + refresh token pattern
- Access token — short-lived (15 minutes). Sent with every request. Stateless validation.
- Refresh token — long-lived (7–30 days). Stored in an httpOnly cookie. Used only to obtain new access tokens.
Refresh token rotation
On every refresh, issue a new refresh token and invalidate the old one. If a stolen refresh token is used after the legitimate client has already rotated it, the server detects the reuse and invalidates the entire family (logout all sessions).
Common mistakes
- Storing JWTs in localStorage — accessible to XSS. Use httpOnly cookies for refresh tokens.
- Long-lived access tokens — 15 minutes is a good default. Not 24 hours.
- No token revocation strategy — needed for logout and account compromise response. Use a short-lived deny-list in Redis.
- Sensitive data in the payload — payloads are Base64-encoded, not encrypted. Never put PII in claims.