RLS & Data Scoping
RLS & Data Scoping
This article explains Row Level Security (RLS) concepts and recommended patterns for ensuring data is always scoped to a tenant/organization.
Why RLS
- RLS enforces data access at the database level so that even if an application bug exists, the DB prevents cross-tenant data leakage. Jobs Map notes that RLS policies enforce data access control and are central to tenant scoping. :contentReference[oaicite:11]{index=11}
Core recommendation
- Every multi-tenant table must include a tenant identifier (for example
org_id). - RLS policies should reference the tenant id inside the user’s auth claims (e.g., the JWT/claims that include
org_id) and the record’sorg_idbefore allowing SELECT/INSERT/UPDATE/DELETE.
Policy design patterns (high-level)
- SELECT/USING policy — ensure rows returned to a user match
org_id. Example (conceptual):
- Allow SELECT when
row.org_id = current_user_org_id.
- INSERT/ WITH CHECK — when inserting, ensure
org_idon the row matches the caller’sorg_id(prevents writing to other tenants). - UPDATE — restrict updates to rows where
org_idmatches user’sorg_id. - Audit columns — keep
created_byandupdated_byand record user id and role for change history.
Note: Implementation details vary by DB/provider. For Supabase/Postgres, RLS can reference JWT claims exposed via the Postgres current_setting('jwt.claims') or Supabase helpers; test the exact claim-access expression in your environment.Best practices
- Fail closed: If the RLS policy cannot determine the user’s tenant, deny access.
- Test cross-tenant scenarios: Use automated tests to assert one tenant cannot read/modify another tenant’s rows even with forged queries.
- Combine RLS with server-side checks: For complex business rules (billing, role-based actions), use both RLS and server-side validation.
Operational checklist
- [ ] Add
org_idto all tenant-scoped tables (jobs, properties, clients, invoices, attachments, payments). - [ ] Create RLS policies for
SELECT,INSERT,UPDATE, andDELETEthat enforceorg_id= caller’sorg_id. :contentReference[oaicite:12]{index=12} - [ ] Ensure JWT/claims include
org_idand test policies in staging with real tokens. - [ ] Maintain migration scripts that create RLS policies as part of the schema.
Offer: example policies
If you want, I can produce explicit example RLS policy SQL for Postgres / Supabase (SELECT, INSERT/ WITH CHECK, UPDATE) tuned to your JWT claim model. This helps speed implementation and avoids common pitfalls (claim retrieval, type casting).
Updated on: 10/01/2026
Thank you!
