Home Arrow Icon Knowledge base Arrow Icon Global Arrow Icon How do I create complex SQL rules for RLS in Supabase
    Supabase SQL Row Level Security RLS PostgreSQL Supabase security RLS policies database security


How do I create complex SQL rules for RLS in Supabase


To create complex SQL rules for Row Level Security (RLS) in Supabase, you can use Postgres' powerful RLS features. Here are some steps and examples to help you get started:

Enable RLS on Tables

1. Create Tables: Create tables in your Supabase database. For example, create a `teams` table and a `members` table.

sql
   CREATE TABLE teams (
       id SERIAL PRIMARY KEY,
       name TEXT
   );

   CREATE TABLE members (
       team_id BIGINT REFERENCES teams,
       user_id UUID REFERENCES auth.users
   );
   

2. Enable RLS: Enable RLS on the tables you want to secure.

sql
   ALTER TABLE teams ENABLE ROW LEVEL SECURITY;

   ALTER TABLE members ENABLE ROW LEVEL SECURITY;
   

Create Policies

1. Basic Policy: Create a basic policy to restrict access to a table based on a column. For example, restrict access to the `teams` table based on the `id` column.

sql
   CREATE POLICY "Team members can view their own team details if they belong to the team."
       ON teams
       FOR SELECT
       TO authenticated
       USING (auth.uid() IN (
           SELECT user_id
           FROM members
           WHERE team_id = id
       ));
   

2. Advanced Policy with Joins: Create a policy that includes table joins. For example, restrict access to the `tasks` table based on the `organization_id` column and the `user_id` column.

sql
   CREATE POLICY "Only allow organizations to create tasks if they have enough quota"
       ON tasks
       AS RESTRICTIVE
       FOR INSERT
       TO authenticated
       WITH CHECK (
           organization_can_create_task(organization_id)
       );
   

Use Security Definer Functions

1. Security Definer Function: Create a security definer function to bypass RLS policies. For example, create a function that can be called by the `service_role` to bypass RLS.

sql
   CREATE OR REPLACE FUNCTION create_task(user_id BIGINT, name TEXT)
       RETURNS tasks AS $$
   BEGIN
       IF current_setting('role') != 'service_role' THEN
           RAISE EXCEPTION 'Only admins can call this function';
       END IF;
       INSERT INTO tasks (user_id, name) VALUES (user_id, name);
       RETURN (SELECT * FROM tasks WHERE id = currval('tasks_id_seq'));
   END;
   $$ LANGUAGE plpgsql SECURITY DEFINER;
   

Restrictive Policies

1. Restrictive Policy: Create a restrictive policy to restrict write access to a table based on a column. For example, restrict write access to the `users` table based on the `id` column.

sql
   CREATE POLICY "Restrict write access to authenticated users"
       ON users
       AS RESTRICTIVE
       FOR INSERT
       TO authenticated
       WITH CHECK (id = auth.uid());
   

Common RLS Policies

1. Restricting Access to a Table Based on a Column: Restrict access to a table based on a column.

sql
   CREATE POLICY "Restrict access to user tasks to their own tasks"
       ON tasks
       FOR SELECT
       TO authenticated
       USING (user_id = auth.uid());
   

2. Restricting Write Access to a Table Based on a Column: Restrict write access to a table based on a column.

sql
   CREATE POLICY "Restrict write access to authenticated users"
       ON users
       AS RESTRICTIVE
       FOR INSERT
       TO authenticated
       WITH CHECK (id = auth.uid());
   

Use db_pre_request

1. db_pre_request: Use `db_pre_request` to simplify complex RLS policies. For example, use it to set a claim that can be used for the rest of the records.

sql
   db_pre_request: function() {
       const user = auth.user();
       const orgId = user.org_id;
       setClaim('orgId', orgId);
   }
   

Example Policy with db_pre_request

1. Policy with db_pre_request: Create a policy that uses `db_pre_request` to set a claim.

sql
   CREATE POLICY "Only allow organizations to create tasks if they have enough quota"
       ON tasks
       AS RESTRICTIVE
       FOR INSERT
       TO authenticated
       WITH CHECK (
           organization_can_create_task(getClaim('orgId'))
       );
   

By following these steps and examples, you can create complex SQL rules for Row Level Security in Supabase to secure your data effectively.

Citations:
[1] https://supabase-sql.vercel.app/rls-policies-with-joins
[2] https://supabase.com/docs/guides/database/postgres/row-level-security
[3] https://makerkit.dev/docs/next-supabase/row-level-security
[4] https://www.reddit.com/r/Supabase/comments/15nem7t/could_supabase_rls_used_for_complex_authorization/
[5] https://docs-ewup05pxh-supabase.vercel.app/docs/guides/auth/row-level-security