Typed Express Middleware With Request State

Extend Express request types through declaration merging so middleware can attach authenticated user data that later handlers read with full type safety.

TypescriptAuth Jwt

Code

snippet
import express, { type NextFunction, type Request, type Response } from "express";

export interface AuthUser {
  id: string;
  roles: string[];
}

declare module "express-serve-static-core" {
  interface Request {
    user?: AuthUser;
  }
}

export function requireAuth(req: Request, res: Response, next: NextFunction): void {
  const token = req.header("authorization")?.replace(/^Bearer /, "");
  if (!token) {
    res.status(401).json({ error: "missing token" });
    return;
  }
  try {
    req.user = verifyToken(token);
    next();
  } catch (error) {
    res.status(401).json({ error: (error as Error).message });
  }
}

function verifyToken(token: string): AuthUser {
  const payload = JSON.parse(Buffer.from(token.split(".")[1], "base64").toString());
  return { id: payload.sub, roles: payload.roles ?? [] };
}

const app = express();
app.use(requireAuth);