Skip to content

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:

LayerRole
Edge FunctionPrimary enforcement — ownership checks, role checks, validation before any write.
RLSDefense-in-depth on every user-facing table, in case a path is missed.
  • Ownership: EFs verify the row belongs to user.id before UPDATE/DELETE.
  • Admin: requireAdmin(req) (checks an admin claim/RPC); admin features live in the admin/ tier and use src/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.jsx and ProtectedAdminRoute.jsx.
  • Feature flags: useFeatureGate() from FeatureGateContext toggles features globally.

UI gating is never the security boundary — the edge function + RLS are. The client is untrusted.