Appearance
Authentication & Authorization
Authentication (who you are)
- Supabase Auth issues the session/JWT. The browser holds it via
src/contexts/SupabaseAuthContext.jsx(useAuth()). - Every Type A edge function re-verifies the JWT server-side with
requireAuth(req)from_shared/auth.ts. The user id always comes from the verified token — never from the request body.
Authorization (what you can do)
Defense-in-depth, two layers — both always required:
| Layer | Role |
|---|---|
| Edge Function | Primary enforcement — ownership checks, role checks, validation before any write. |
| RLS | Defense-in-depth on every user-facing table, in case a path is missed. |
- Ownership: EFs verify the row belongs to
user.idbefore UPDATE/DELETE. - Admin:
requireAdmin(req)(checks an admin claim/RPC); admin features live in theadmin/tier and usesrc/lib/customSupabaseClient.js. - Roles in RLS: policies often gate on
auth.uid()and an admin JWT claim.
Front-end gating
- Route protection:
src/components/routes/ProtectedRoute.jsxandProtectedAdminRoute.jsx. - Feature flags:
useFeatureGate()fromFeatureGateContexttoggles features globally.
UI gating is never the security boundary — the edge function + RLS are. The client is untrusted.