JWT and Session Auth Patterns

Comparison of JWT vs session auth, secure token storage, refresh token patterns, and common pitfalls.

Syntax

environments-and-security
// JWT structure | sign | verify | refresh | storage

Example

environments-and-security
// JWT: three parts separated by dots
// header.payload.signature
// eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1c2VyMTIzIn0.abc123

// Sign a JWT
import jwt from 'jsonwebtoken';
const token = jwt.sign(
  { userId: user.id, role: user.role },  // payload
  process.env.JWT_SECRET,                // secret
  { expiresIn: '15m' }                   // short-lived access token
);

// Verify a JWT
try {
  const decoded = jwt.verify(token, process.env.JWT_SECRET);
  req.user = decoded;
} catch (err) {
  return res.status(401).json({ error: 'Invalid token' });
}

// Refresh token pattern
// Access token: short-lived (15min), stored in memory
// Refresh token: long-lived (7 days), stored in httpOnly cookie

// SECURE cookie storage
res.cookie('refresh_token', refreshToken, {
  httpOnly: true,   // not accessible via JS
  secure: true,     // HTTPS only
  sameSite: 'strict', // CSRF protection
  maxAge: 7 * 24 * 60 * 60 * 1000, // 7 days
});

// NEVER store tokens in localStorage (XSS vulnerable)
// NEVER put sensitive data in JWT payload (it's base64 decoded, not encrypted)