# Authentication & Authorization at the Framework Level (Part 1: Guards and Middleware)

This topic assumes familiarity with `backend/frameworks/06-middleware` (the mechanism this topic builds on directly) and `backend/frameworks/09-dependency_injection`. It does **not** re-teach token mechanics — `security/security/02-jwt` and `security/security/03-oauth` cover what a JWT is and how OAuth2 flows work in depth. This topic is about how a *framework* enforces those tokens at the route level: where in the request chain identity gets resolved, and how a route gets protected.

## 1. Two Separate Questions, Two Separate Mechanisms

"Who is this caller" (authentication) and "may this caller do this" (authorization) are resolved at different points and by different framework constructs, even though both commonly get bundled under one guard/middleware in simple cases:

```
Authentication -> resolves ONE identity from the request, early, before the handler runs
Authorization  -> checks that identity against what THIS specific route/resource requires
```

`backend/api-design/10-api_security` covers this same authentication/authorization split from the API-design and attack-surface angle (BOLA, mass assignment); this topic covers the framework mechanics that make the check actually happen before a handler ever executes.

## 2. Middleware/Guards: Intercepting Before the Handler Runs

The framework mechanism for "run this check before the route handler, and block the request if it fails" is the same middleware chain covered generally in `backend/frameworks/06-middleware`, specialized here for auth:

```ts
// Express: an auth middleware function
async function requireAuth(req: Request, res: Response, next: NextFunction) {
  const token = req.headers.authorization?.replace("Bearer ", "");
  if (!token) return res.status(401).json({ error: "missing token" });
  try {
    req.user = await verifyJwt(token); // attaches the resolved identity to the request
    next(); // only calls the actual handler if verification succeeded
  } catch {
    res.status(401).json({ error: "invalid or expired token" });
  }
}

app.get("/orders", requireAuth, (req, res) => {
  res.json(orderService.listForUser(req.user.id)); // req.user is guaranteed to exist here
});
```

```ts
// NestJS: a Guard plays the identical role, integrated with the DI container
@Injectable()
class AuthGuard implements CanActivate {
  canActivate(context: ExecutionContext): boolean {
    const req = context.switchToHttp().getRequest();
    const token = req.headers.authorization?.replace("Bearer ", "");
    if (!token) return false; // NestJS turns a `false` return into a 403 automatically
    req.user = verifyJwtSync(token); // simplified for illustration
    return true;
  }
}

@UseGuards(AuthGuard)
@Controller("orders")
class OrderController { /* every route on this controller now requires auth */ }
```

Both examples do the same job: run before the handler, resolve identity from the token, attach it somewhere the handler can read it, and short-circuit the request (401/403) if resolution fails — the handler body itself never has to think about token verification at all.

## 3. Extracting the Authenticated User Inside a Handler

Once middleware/a guard has attached the resolved identity to the request, handlers access it directly rather than re-parsing the token themselves:

```ts
// Express
app.get("/me", requireAuth, (req, res) => {
  res.json({ id: req.user.id, email: req.user.email }); // req.user was set by requireAuth
});

// NestJS: a parameter decorator is the idiomatic way to pull it out
@Get("me")
getProfile(@CurrentUser() user: User) { // @CurrentUser reads req.user, set by AuthGuard
  return { id: user.id, email: user.email };
}
```

This is the practical payoff of resolving authentication once, centrally, rather than re-verifying a token inside every handler: every downstream handler trusts that if it was reached at all, `req.user` is already populated and valid.

## 4. Protecting a Whole Controller vs. a Single Route

Guards/middleware can apply at different granularities — globally (every route in the app), per-controller (every route on one controller), or per-route (one specific handler):

```ts
// Global: every route in the entire app requires auth
app.use(requireAuth);

// Per-controller: every route on OrderController requires auth, nothing else does
@UseGuards(AuthGuard)
@Controller("orders")
class OrderController {}

// Per-route: only THIS one handler requires auth
@Controller("public")
class PublicController {
  @Get("health")
  health() { return { ok: true }; } // no guard — publicly accessible

  @UseGuards(AuthGuard)
  @Get("admin-stats")
  adminStats() { /* ... */ } // guarded individually
}
```

The right granularity is whichever minimizes repetition for the actual shape of the API — an app that's almost entirely authenticated except for a login/health-check endpoint usually applies auth globally and explicitly excludes the few public routes, rather than decorating every protected route individually.

## Common Pitfalls

1. **Re-verifying the token inside individual handlers instead of trusting the guard/middleware.** Defeats the point of centralizing authentication — every handler ends up with duplicated, easy-to-get-wrong verification logic.
2. **Forgetting to apply the guard to a new route added later.** Per-route guards require remembering to add them every time; a controller-level or global guard with explicit opt-outs for public routes is generally safer against this exact mistake.
3. **Trusting `req.user` without confirming a guard actually ran.** A handler that reads `req.user` on a route where the guard was accidentally omitted gets `undefined` and likely crashes or, worse, silently treats the request as some default identity.
4. **Conflating "guard returned true" with full authorization.** A guard resolving *who* the caller is says nothing about whether they're allowed to touch *this specific resource* — that's a separate, per-operation check (part 2 of this topic).

## Quick Reference

```
Authentication  -> resolved ONCE, by middleware/a guard, before the handler runs
Middleware/Guard -> intercepts the request, verifies the token, attaches identity, or blocks (401/403)
Handler          -> trusts identity is already resolved; never re-verifies the token itself
Granularity      -> global, per-controller, or per-route — pick whichever minimizes repetition
```
