Articles on: Security & Admin

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’s org_id before allowing SELECT/INSERT/UPDATE/DELETE.




Policy design patterns (high-level)

  1. SELECT/USING policy — ensure rows returned to a user match org_id. Example (conceptual):
  • Allow SELECT when row.org_id = current_user_org_id.
  1. INSERT/ WITH CHECK — when inserting, ensure org_id on the row matches the caller’s org_id (prevents writing to other tenants).
  2. UPDATE — restrict updates to rows where org_id matches user’s org_id.
  3. Audit columns — keep created_by and updated_by and 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_id to all tenant-scoped tables (jobs, properties, clients, invoices, attachments, payments).
  • [ ] Create RLS policies for SELECT, INSERT, UPDATE, and DELETE that enforce org_id = caller’s org_id. :contentReference[oaicite:12]{index=12}
  • [ ] Ensure JWT/claims include org_id and 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

Was this article helpful?

Share your feedback

Cancel

Thank you!