Recent

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);

JWT vs Session Cookies

| Aspect | JWT | Session Cookies ||--------|-----|----------------|| Storage | Client-side (localStorage/cookies) | Server-side || Scalability | Stateless, scales easily | Requires shared session store || Revocation | Complex (requires blocklist) | Easy (delete session) || Size | Larger (token in every request) | Small (session ID only) || Security | Vulnerable to XSS | httpOnly cookies protect against XSS |

Access Tokens vs Refresh Tokens

The best practice is to use two tokens:

// Access token: short-lived (15-60 min), contains claims
// Refresh token: long-lived (days/weeks), used to get new access tokens

// Example flow:
1. Login → returns access_token (15min) + refresh_token (7days)
2. API calls use access_token
3. When access_token expires → use refresh_token to get new pair
4. Refresh token can be invalidated (logout, security breach)

Common JWT Libraries

  • Node.js: jsonwebtoken, jose (universal)
  • Python: PyJWT, python-jose
  • Java: jjwt, java-jwt
  • Go: golang-jwt/jwt
  • Rust: jsonwebtoken

Security Checklist

  • Always use HTTPS — Tokens are credentials, protect them in transit
  • Validate algorithm — Prevent algorithm confusion attacks
  • Check expiration — Always verify exp claim
  • Verify issuer — Check iss matches your expected value
  • Verify audience — Check aud is for your API
  • Use secure storage — httpOnly cookies over localStorage
  • Implement refresh token rotation — Prevents token reuse attacks

Troubleshooting Common Issues

"Token expired" error

Check the server clock is synchronized. JWT validation compares against server time.

"Invalid signature"

Verify the secret/key matches exactly what was used to sign the token.

"Token not before" error

The nbf (not before) claim is set in the future. Wait or adjust server time.

Algorithm confusion attack

Always specify and validate the expected algorithm. Don't let clients choose the algorithm.

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!