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.