Express

Lesson 08

Auth middleware boundaries

Authenticate once in middleware and pass a safe user context to route handlers.

Good Code

src/auth/require-user.ts
import type { NextFunction, Request, Response } from "express";

export async function requireUser(
  req: Request,
  res: Response,
  next: NextFunction,
) {
  const session = await sessions.findFromHeader(req.get("authorization"));

  if (!session) {
    res.status(401).json({ error: { message: "Authentication required." } });
    return;
  }

  res.locals.user = {
    id: session.userId,
    role: session.role,
  };
  next();
}

Bad Code

src/reviews/router.ts
router.post("/:id/approve", async (req, res) => {
  const token = req.get("authorization");
  const session = await sessions.findFromHeader(token);

  if (!session || session.role !== "maintainer") {
    res.status(403).json({ error: "Forbidden" });
    return;
  }

  const review = await service.approveReview(req.params.id, session.userId);
  res.json({ data: review });
});

Review Notes

What to review

Good Code

The good version authenticates in middleware and stores only the user context downstream routes need.

Bad Code

The bad version reparses credentials inside the route, mixing authentication, authorization, and review approval in one handler.

Takeaways

  • Routes should consume trusted auth context instead of reparsing credentials.