Authentication — API Keys & JWT
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.