Authentication
Current state (being replaced)
Section titled “Current state (being replaced)”Two incompatible auth systems operate simultaneously:
| System | Scope | Token type | Storage |
|---|---|---|---|
| Passport.js local strategy | Backend API | Express session cookie | MemoryStore (volatile) |
| Supabase Auth | Frontend UI | JWT + refresh token | localStorage |
These don’t share state. The backend can’t verify Supabase JWTs; the frontend can’t verify Passport sessions. A hardcoded admin123 bypass exists in the Passport strategy.
Target: Cloudflare Access
Section titled “Target: Cloudflare Access”Per ADR-001, Cloudflare Access becomes the single authentication layer.
How it works
Section titled “How it works”- Staff navigates to the dashboard URL
- Cloudflare Access gate intercepts — redirects to Google SSO if no valid session
- After successful Google login, Access issues a JWT
- Every subsequent request includes the JWT via
Cf-Access-Jwt-Assertionheader - Worker middleware validates the JWT and extracts identity
JWT validation middleware
Section titled “JWT validation middleware”import { Context, Next } from 'hono';
interface Principal { email: string; sub: string; iat: number; exp: number;}
export function cfAccessMiddleware() { return async (c: Context, next: Next) => { const token = c.req.header('Cf-Access-Jwt-Assertion'); if (!token) { return c.json({ error: 'Missing Access token' }, 401); }
const principal = await validateAccessJwt(token, c.env.CF_ACCESS_AUD); if (!principal) { return c.json({ error: 'Invalid Access token' }, 403); }
c.set('principal', principal); await next(); };}Key details
Section titled “Key details”- Header over cookie: Cloudflare recommends validating
Cf-Access-Jwt-Assertionbecause theCF_Authorizationcookie is not guaranteed to be passed - No auth UI: The React app has no login page — Access handles authentication before the app loads
- No RBAC in v1: All authenticated staff have equal access (explicitly deferred per SOW)
- Service tokens: For cron/queue/admin automation, Access service tokens authenticate machine-to-machine calls
Frontend changes
Section titled “Frontend changes”- Remove
@supabase/supabase-jsauth imports - Remove
AuthContext,AuthProvider,useAuthhook - Remove
/authand/reset-passwordroutes - Remove
ProtectedRoutewrapper (all routes are protected by Access) - API client automatically forwards Access headers when Pages + Workers share a zone
What this eliminates
Section titled “What this eliminates”- Passport.js + express-session + MemoryStore
- Supabase Auth (JWT issuance, password reset flows)
- Hardcoded
admin123bypass - Split-brain identity model
- Session volatility (lost on restart)