JWTs and the requireAuth middleware
A JWT is a signed string that carries a small payload and an expiration. The server creates it on login. The client sends it back on every subsequent request in an Authorization header. The server verifies the signature without hitting the database.
The auth handshake
Login once to get a token. Send the token with every protected request. The server verifies the signature and lets you through.
Important detail: JWTs are signed, not encrypted. Anyone can decode the payload with an online tool. The signature just proves the token was not tampered with. Never put secrets in a JWT payload. User id, role, and expiration are fine. Credit card numbers are not.
export function requireAuth(req: Request, res: Response, next: NextFunction) {
const authHeader = req.headers.authorization;
if (!authHeader || !authHeader.startsWith('Bearer ')) {
res.status(401).json({ error: 'Unauthorized: Missing or invalid token' });
return;
}
const token = authHeader.split(' ')[1];
try {
const payload = jwt.verify(token, JWT_SECRET) as Request['user'];
req.user = payload;
next();
} catch (err) {
res.status(403).json({ error: 'Forbidden: Invalid or expired token' });
}
}Extract the Bearer token, verify it, attach the user to req for downstream handlers.
Read the middleware carefully. Grab the Authorization header. Split the Bearer prefix off. Verify the token with jwt.verify, which checks both the signature and the expiration. On success, attach the decoded payload to req.user and call next. On failure, respond with 401 or 403 and never call next. That is the entire auth gate.
Quiz: Quiz
Loading practice…