Authentication — API Keys & JWT

🔗 REST API Lesson 6 Intermediate

Authentication answers "Who are you?" REST APIs must be stateless, which means traditional session cookies don't apply. The two most common methods are API Keys for machine-to-machine auth and JWT (JSON Web Tokens) for user identity.

1 API Keys

API keys are simple opaque strings passed in a header or query param. Best for server-to-server communication:

HTTP — API Key Authentication
# Preferred: send in header
GET /api/v1/data
X-API-Key: ak_live_9f8e7d6c5b4a3210

# Alternative: query param (less secure — visible in logs)
GET /api/v1/data?api_key=ak_live_9f8e7d6c5b4a3210
JavaScript — API Key Middleware (Express)
async function apiKeyAuth(req, res, next) {
  const key = req.headers["x-api-key"];
  if (!key) return res.status(401).json({ error: "API key required" });

  // Look up key in database
  const apiKey = await ApiKey.findOne({ key, isActive: true });
  if (!apiKey) return res.status(401).json({ error: "Invalid API key" });

  req.client = apiKey.owner;
  next();
}
2 JWT — JSON Web Tokens

A JWT is a self-contained token with three Base64-encoded parts: Header.Payload.Signature:

JavaScript — JWT Sign & Verify
const jwt = require("jsonwebtoken");

// --- SIGN (on login) ---
const accessToken = jwt.sign(
  { userId: user.id, role: user.role, email: user.email }, // payload
  process.env.JWT_SECRET,                                  // secret
  { expiresIn: "15m", issuer: "api.example.com" }          // options
);

// --- VERIFY (in middleware) ---
function verifyToken(req, res, next) {
  const auth = req.headers.authorization;
  if (!auth || !auth.startsWith("Bearer ")) {
    return res.status(401).json({ error: "Token required" });
  }
  try {
    const decoded = jwt.verify(auth.split(" ")[1], process.env.JWT_SECRET);
    req.user = decoded;
    next();
  } catch (err) {
    const msg = err.name === "TokenExpiredError" ? "Token expired" : "Invalid token";
    res.status(401).json({ error: msg });
  }
}
3 Access + Refresh Token Strategy
REST — Token Flow
1. POST /auth/login  -> { accessToken (15min), refreshToken (7d) }
2. Client stores refreshToken in httpOnly cookie (not localStorage!)
3. Client sends accessToken in Authorization header with every request
4. When accessToken expires, client calls:
   POST /auth/refresh  (sends refreshToken cookie)
   -> { new accessToken }
5. On logout:
   POST /auth/logout   -> invalidate refreshToken in DB
4 Code Challenge
Challenge: Build a complete POST /auth/login and POST /auth/refresh flow using Express and the jsonwebtoken package. The refresh token should be stored as an httpOnly, SameSite=Strict cookie.