HomeGuidesSupabase RLS testing
Supabase RLS testing

Test what a signed-in user must not be allowed to do.

A Supabase policy is tenant-safe only when it relates the current identity to the tenant that owns the target row. Checking auth.uid() somewhere in a query is not enough if that relationship is missing.

Create two tenants and two users

Give user A membership only in tenant A and user B membership only in tenant B. Seed one protected row per tenant, then run every operation as both users.

  • Confirm each user can perform the intended operation inside their own tenant
  • Replace the row or tenant identifier with the other tenant's value
  • Expect zero rows, a policy violation, or an application-safe not-found response
  • Repeat with changed JWT metadata and direct API requests

Correlate membership to the row being accessed

The membership check must compare against the protected row's tenant key. A policy that merely proves the user belongs to any organization can authorize every row.

Tenant-correlated SELECT policysql
create policy "members read projects"
on public.projects for select
to authenticated
using (
  exists (
    select 1
    from public.organization_memberships m
    where m.organization_id = projects.organization_id
      and m.user_id = auth.uid()
  )
);

Test USING and WITH CHECK separately

USING controls which existing rows an UPDATE or DELETE can target. WITH CHECK controls whether the proposed INSERT or updated row is allowed. Testing only reads leaves tenant-key reassignment and cross-tenant inserts uncovered.

Check the migration before runtime testing

BoundaryCI catches deterministic final-state mistakes before a disposable Supabase environment is created. Runtime tests remain valuable for claims, joins, RPC, storage, and application behavior that static analysis cannot prove.

Scan migrations in CIbash
npx boundaryci scan supabase --profile supabase --fail-on high
Protect the boundary

Make tenant isolation a repeatable pull-request check.

Run the deterministic scanner locally without database credentials, then add Cloud only when your team needs shared history.

Scan Supabase migrations Read the quickstart