JWT (JSON Web Token)

A compact, URL-safe token format for securely transmitting information between parties.

JWT (JSON Web Token) is a compact, URL-safe token format for securely transmitting information between parties. It's commonly used for authentication - after login, server issues a JWT that client sends with subsequent requests to prove identity.

Token Structure

A JWT has three parts separated by dots: header.payload.signature

Header: Token metadata - type (JWT) and signing algorithm (HS256, RS256).

Payload: Claims - data about the user and token. Standard claims include sub (subject/user ID), exp (expiration), iat (issued at), iss (issuer).

Signature: Cryptographic hash of header + payload using a secret key. Prevents tampering.

How JWT Authentication Works

  1. User logs in with credentials
  2. Server validates credentials, creates JWT with user info
  3. Server sends JWT to client
  4. Client stores JWT (localStorage, cookie, memory)
  5. Client sends JWT in Authorization header: Bearer <token>
  6. Server verifies signature and extracts user info
  7. Server processes request based on user identity

Signing Algorithms

AlgorithmTypeUse Case
HS256SymmetricSame secret for sign/verify. Simple, fast. Single server.
RS256AsymmetricPrivate key signs, public key verifies. Distributed systems.
ES256AsymmetricLike RS256 but smaller keys, faster. Mobile apps.

Token Expiration Strategy

Short-lived access tokens (15-60 min): Limits damage if stolen. User stays logged in with refresh tokens.

Long-lived refresh tokens (7-30 days): Stored securely, used only to get new access tokens. Can be revoked.

Sliding expiration: Each request extends expiration. Active users stay logged in.

Security Best Practices

Never store sensitive data in payload: JWTs are encoded, not encrypted. Anyone can decode and read the payload.

Use HTTPS only: Tokens in transit can be intercepted over HTTP.

Set expiration: Always include exp claim. Short expiration limits attack window.

Validate all claims: Check iss, aud, exp on every request. Don't just verify signature.

Secure storage: HttpOnly cookies for web (prevents XSS). Secure storage for mobile.

Use strong secrets: 256+ bits for HS256. Don't commit to git.

Common Mistakes

1. Storing JWTs in localStorage: Vulnerable to XSS attacks. Prefer HttpOnly cookies.

2. Not validating expiration: Expired tokens should be rejected. Always check exp claim.

3. Trusting the algorithm header: Attackers can change to "none". Whitelist allowed algorithms server-side.

4. Huge payloads: JWTs go in every request. Keep payload small (< 1KB).

5. No revocation strategy: JWTs are stateless - can't invalidate before expiration. Use short expiration or token blacklist.

When to Use JWT

Good fit:

  • Stateless authentication
  • Microservices (pass user context)
  • Single sign-on (SSO)
  • API authentication

Consider alternatives:

  • Session cookies for traditional web apps
  • OAuth for third-party access
  • API keys for service-to-service

Code Examples

JWT Authentication with Verification

import jwt from 'jsonwebtoken';

const SECRET = process.env.JWT_SECRET;

// Create token after login
function createToken(user) {
  return jwt.sign(
    {
      sub: user.id,
      email: user.email,
      role: user.role
    },
    SECRET,
    { expiresIn: '1h' }
  );
}

// Verify token middleware
function authenticate(req, res, next) {
  const header = req.headers.authorization;
  if (!header?.startsWith('Bearer ')) {
    return res.status(401).json({ error: 'No token provided' });
  }

  const token = header.slice(7);

  try {
    const payload = jwt.verify(token, SECRET, {
      algorithms: ['HS256'] // Whitelist algorithm
    });
    req.user = payload;
    next();
  } catch (err) {
    if (err.name === 'TokenExpiredError') {
      return res.status(401).json({ error: 'Token expired' });
    }
    return res.status(401).json({ error: 'Invalid token' });
  }
}