DEV Community

Domonique Luchin
Domonique Luchin

Posted on

Row Level Security Is Not Optional: How I Locked Down a Multi-Tenant Supabase App

If you are using Supabase and you have not enabled Row Level Security on every table, stop what you are doing and fix that right now. I am serious.

Supabase exposes your Postgres database through a REST API using the anon key. That key is public. It is in your frontend code. Anyone can see it. The only thing standing between your data and the internet is RLS.

What RLS Does

Row Level Security is a Postgres feature that adds WHERE clauses to every query automatically. You define policies that say "this user can only see rows where user_id matches their auth ID." Postgres enforces it at the database level. No middleware. No application logic. Just policy.

My Setup

I run a multi-tenant system. 6 businesses, shared database, different contexts. Here is how I structured it:

Brand Isolation

CREATE POLICY "Users see own brand data"
ON leads FOR SELECT
USING (brand_id IN (
  SELECT brand_id FROM user_brands
  WHERE user_id = auth.uid()
));
Enter fullscreen mode Exit fullscreen mode

Every table that holds business data has a brand_id column. Users only see data for brands they are assigned to.

Service Role Separation

Edge functions that need cross-brand access use the service role key. That key bypasses RLS. It never touches the frontend. Every view that edge functions expose uses SECURITY INVOKER so the calling user's permissions apply.

Foreign Key Indexes

This is the one people miss. If you have RLS policies that join against other tables, those joins need indexes. Without them, your queries slow to a crawl as your data grows. I added foreign key indexes on every table during a security hardening pass.

The Audit

I ran a full security audit across both of my Supabase projects:

  1. Listed every table without RLS enabled
  2. Added policies to each one
  3. Changed all views to SECURITY INVOKER
  4. Added missing foreign key indexes
  5. Tested with the anon key to verify no data leaks

Total time: about 4 hours. That is 4 hours to prevent a data breach that could end your business.

The Rule

If a table has data that belongs to a user or a brand or an organization, it gets RLS. No exceptions. No "I will add it later." The moment you create the table, you add the policy.

Supabase makes this easy. Do not skip it.

Top comments (0)