Skip to content

Multi Tenancy and Row Level Security

Claude edited this page Sep 14, 2026 · 2 revisions

Multi-Tenancy & Row-Level Security (RLS)

TL;DR: every tenant-owned table has Postgres row-level security enabled and forced. The app connects as a non-owner role so RLS applies to it, and each request sets the current org via SET LOCAL for one transaction.

Every tenant-owned table has Postgres row-level security enabled and forced (FORCE ROW LEVEL SECURITY — without this, the table's own owner role bypasses RLS regardless of the policy). The app connects as a separate, non-owner dmarc_app role specifically so RLS applies to it. Each request sets app.current_org_id via SET LOCAL for the duration of one transaction; a small number of cross-org background jobs (the DNS check sweep, domain verification sweep, retention purge) instead set app.is_platform_admin = true, which every policy also accepts.

backend/tests/test_rls.py runs against a real Postgres as the non-owner dmarc_app role: cross-tenant reads are hidden, an unset org context fails closed, the platform-admin bypass works, a cross-tenant write is refused by the policy's WITH CHECK, and a meta-guard asserts every table with an organization_id column has FORCE RLS and a policy, so a PR that adds a tenant-owned table but forgets its policy fails CI. See Running the Test Suite.


← Core Concepts · Home

Clone this wiki locally