Skip to main content
Scope of this API vs. production RLS state. This endpoint (and the RLS_TABLES registry behind it, src/lib/db/rls.ts) only covers Prisma-modeled tables that were registered in that array before 2026-07-10. As of 2026-07-10, RLS is enabled and forced on all 111 target tables in production — this endpoint’s registry plus 51 additional tables (e.g. consent_records, webauthn_credentials, shopify_shops, tenant_settings) that were enabled directly via prisma/manual-sql/35_rls_track_a.sql and are not tracked by this API. Tables with a tenantId/tenant_id column got the standard tenant_isolation policy described below; tables without one (e.g. NextAuth tables, child tables FK’d to a tenant-scoped parent) got default-deny RLS instead. Supabase’s Data API (the anon/PostgREST HTTP surface that could otherwise reach any of these tables directly, bypassing the app) has also been disabled at the source.This does not mean RLS governs the app’s own queries. The app’s Postgres connection uses a BYPASSRLS-class role by design, so none of these policies constrain what the application itself can read or write — they only stop the anon/PostgREST path and any other non-bypass connection. Tenant isolation for the app’s own traffic is still enforced at the application layer (the where: { tenantId } convention, backed by isolation tests) via requireTenant(). withTenantRLS() (src/lib/db/rls.ts) exists as an opt-in helper for scoping a transaction’s session variable, but it has no production call sites yet — app-query-level RLS enforcement is a separate, deliberately-not-yet-executed initiative.

GET /api/v1/admin/rls

Check RLS status on the tables tracked by this API (RLS_TABLES in src/lib/db/rls.ts). Returns which of those tables have RLS enabled, forced, and which have the tenant_isolation policy. This is a subset of all RLS-protected tables in production — see the scope note above.

Response

Summary Fields

FieldTypeDescription
totalTablesintegerTotal number of tenant-scoped tables
rlsEnabledintegerTables with RLS enabled
rlsForcedintegerTables with FORCE RLS (applies even to table owners)
withPolicyintegerTables with the tenant_isolation policy
missingRLSstring[]Table names missing RLS or the isolation policy

Roles

admin only

POST /api/v1/admin/rls

Enable RLS on all tables tracked by this API (RLS_TABLES). This is idempotent and safe to call multiple times. For each table, it:
  1. Enables RLS (ALTER TABLE ... ENABLE ROW LEVEL SECURITY)
  2. Forces RLS for table owners (ALTER TABLE ... FORCE ROW LEVEL SECURITY)
  3. Creates a tenant_isolation policy scoped to the session variable app.current_tenant_id:
    The current_setting(...) call is wrapped in a scalar subquery so Postgres evaluates it once per query (an InitPlan) instead of once per row. current_setting(..., true) returns NULL when the variable isn’t set, and NULL never equals a tenant ID — so a connection with no tenant context set sees zero rows (fail-safe), and the WITH CHECK clause applies the same rule to inserts/updates.

Response

Response Fields

FieldTypeDescription
successbooleantrue if no tables failed
enabledstring[]Tables where RLS was successfully enabled
failedstring[]Tables where RLS enablement failed
totalTablesintegerTotal number of tenant-scoped tables
An audit log entry is created for the operation.

Roles

admin only
RLS enforcement depends on the PostgreSQL session variable app.current_tenant_id being set on a connection (via set_config('app.current_tenant_id', ..., true)) before that connection’s queries can be tenant-scoped by these policies. The platform’s own Prisma client does not set this variable — it connects with a BYPASSRLS-class role, so these policies don’t constrain it either way. This session variable only matters for connections that are both non-bypass and have RLS enabled/forced on the tables they query (e.g. the anon/PostgREST path, or a future non-bypass role under Track B). Tenant isolation for the app’s own queries is enforced by the application-layer where: { tenantId } convention, not by this session variable.
See also: Admin | Security