# Express route-protection discipline

## getAuth() returns, it does not reject

`getAuth(req)` gives you `{ isAuthenticated, userId }`. On a signed-out request `isAuthenticated` is false and `userId` is null. It never throws, never redirects, never sends a 401. Your handler must do all three decisions:

```ts
const { isAuthenticated, userId } = getAuth(req)
if (!isAuthenticated || !userId) {
  res.status(401).json({ error: 'Unauthorized' })
  return
}
```

If a route "works for signed-out users", the check is missing, not broken. Grep every route for the `isAuthenticated` guard; `clerkMiddleware()` alone protects nothing, it only attaches auth state.

## getUser() hits the network

`clerkClient.users.getUser(userId)` calls Clerk's Backend API on every invocation. In a hot route that means a network round trip per request plus rate-limit exposure.

Checklist:
- Only call it when you need fresh profile data. The session token already carries `userId` and basic claims; use those for identity checks.
- Cache the User object with a short TTL (tens of seconds) keyed by userId if a route needs profile fields repeatedly.
- For writes or security decisions, prefer a fresh fetch or the webhook-synced copy in your own DB over a long-cached profile.

## Cross-origin APIs

If your Express API serves a different origin than the frontend, the session arrives as a Bearer header, not a cookie. Verify with `authorizedParties` set to your frontend origins; Clerk's docs flag unset authorized parties as a CSRF risk.