Authentication
Cloudflare Access JWT validation, mock-user fallback, and fund-level access control.The MVP and full Hugo deployments are fronted by Cloudflare Access; review adds a password gate for lawyer review. Requests to mvp.hugo.nordiclawfirm.com must carry a valid Access identity or approved service/add-in token when REQUIRE_CF_ACCESS=true. App identity is resolved by src/middleware/auth.ts from the mapped Access email, app cookie, add-in session, or local fallback.
Production mode
When REQUIRE_CF_ACCESS=true (set in wrangler.toml), the worker enforces a strict three-mode dispatch in src/middleware/auth.ts:
- Valid Access identity: accept
CF-Access-JWT-Assertionor the Access-authenticated email header, then resolve the application user from theuserstable. - Service token or add-in bearer: allow approved machine/add-in access without relying on browser cookies, then resolve app identity through the existing user/session paths.
- No accepted identity: returns 401 Unauthorized immediately. This is the fail-closed safety net — if CF Access is ever misconfigured (policy flipped, tunnel rerouted), the worker refuses the request rather than falling through to a default user.
Auth-relevant DB calls go through the retry-wrapped proxy (c.var.db if available, else retryableDB(c.env.DB)), so transient D1 errors on the first query of a request don't surface as 500s.
Local development
When REQUIRE_CF_ACCESS is not "true" (e.g. local wrangler dev with .dev.vars), the worker falls back to a mock-user system so a fresh D1 still boots:
- A
hugo_user_idcookie selects the user from theuserstable (regex-capped at 64 chars) - If absent, defaults to
seed_user_alice; a fresh empty D1 falls through to an admin dev passthrough so the app can boot - This branch is gated on
REQUIRE_CF_ACCESS !== 'true'— in production it never fires - See
.dev.vars.examplefor the keys to set locally
Fund access control
| User type | Access | Enforcement |
|---|---|---|
| Admin | All funds | Bypass fundAccessMiddleware |
| Full access | All funds (full_access = 1) |
Bypass fundAccessMiddleware |
| Standard user | Only granted funds | user_funds table check on all /funds/:fundSlug/* routes |
The fundContextMiddleware enforces access control on all /funds/:fundSlug/* routes. It resolves the slug to a canonical fund id, loads the user's fund grants from the user_funds table, and returns 403 if the user does not have access to the requested fund.
Auth flow summary
- Request arrives at Cloudflare Access edge or the review password gate
- CF Access validates identity (human SSO or service token) and passes Access headers to the Worker
- Hugo worker's
authMiddlewareclassifies the perimeter auth kind, including add-in bearer sessions - If
REQUIRE_CF_ACCESS=trueand neither is present: 401 - App identity resolution checks review login, add-in session, mapped Access email, app cookie, seed fallback, then empty-D1 admin passthrough
fundContextMiddlewarechecksuser_fundsfor route-specific fund access- Admin-gated routes additionally check
userRole === 'admin' - Request proceeds or 403
Tested guarantees
tests/middleware/auth.test.ts and tests/middleware/review-login.test.ts cover fail-closed auth, review login, mapped-user lookup, local-dev fallback, and the c.var.db retry-wrapped DB usage.