Skip to content

Authentication

Two incompatible auth systems operate simultaneously:

SystemScopeToken typeStorage
Passport.js local strategyBackend APIExpress session cookieMemoryStore (volatile)
Supabase AuthFrontend UIJWT + refresh tokenlocalStorage

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.

Per ADR-001, Cloudflare Access becomes the single authentication layer.

  1. Staff navigates to the dashboard URL
  2. Cloudflare Access gate intercepts — redirects to Google SSO if no valid session
  3. After successful Google login, Access issues a JWT
  4. Every subsequent request includes the JWT via Cf-Access-Jwt-Assertion header
  5. Worker middleware validates the JWT and extracts identity
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();
};
}
  • Header over cookie: Cloudflare recommends validating Cf-Access-Jwt-Assertion because the CF_Authorization cookie 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
  • Remove @supabase/supabase-js auth imports
  • Remove AuthContext, AuthProvider, useAuth hook
  • Remove /auth and /reset-password routes
  • Remove ProtectedRoute wrapper (all routes are protected by Access)
  • API client automatically forwards Access headers when Pages + Workers share a zone
  • Passport.js + express-session + MemoryStore
  • Supabase Auth (JWT issuance, password reset flows)
  • Hardcoded admin123 bypass
  • Split-brain identity model
  • Session volatility (lost on restart)