Developer Guides

Implementing Supabase Row Level Security Policies

Learn how to set up and verify Row Level Security (RLS) policies in Supabase to efficiently secure your data.

5 min read

Implementing Row Level Security (RLS) in Supabase allows you to secure your database tables by controlling access to individual rows based on a user’s identity or custom logic. This guide will walk you through the process of enabling and testing RLS policies using Supabase, ensuring that your data remains secure and only accessible to authorized users.

Prerequisites

Before we begin, ensure you have the following:

prerequisites

  • Access to a Supabase account.
  • Familiarity with PostgreSQL concepts.
  • A public anon key already set up in Supabase.
  • Basic SQL syntax knowledge.
  • A table structure to secure, such as post or comment.

Steps for Implementing RLS Policies in Supabase

Follow these steps to enable and configure Supabase Row Level Security (RLS) policies:

steps

  1. Enable Row-Level Security for a Table
    Go to the Supabase dashboard, select your project, and navigate to the Table Editor. Choose the table you want to secure (e.g., post), then click Enable Row Level Security.

  2. Create a Policy for User-Specific Access
    Once RLS is enabled, no operations (SELECT, INSERT, UPDATE, DELETE) are allowed by default. Use a policy to define access rules:

    sql
    CREATE POLICY "Enable all actions for user" 
    ON public.post 
    FOR ALL 
    USING (auth.uid() = user_id)
    WITH CHECK (auth.uid() = user_id);

    This allows users to access or modify rows where user_id matches their authenticated ID.

  3. Test the Policy for Row Access
    Attempt to fetch rows via your API. Users should only see the rows they are authorized to access:

    bash
    curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
    'https://your-project.supabase.co/rest/v1/post'
  4. Specify Policies for Read-Only Access to Additional Rows
    To allow users to see published posts:

    sql
    CREATE POLICY "Enable read access to published posts"
    ON public.post
    FOR SELECT
    USING (is_published = TRUE);
  5. Implement Policies for Related Tables
    For associated tables like comments, you can use subqueries:

    sql
    CREATE POLICY "View comments for visible posts"
    ON public.comment
    FOR SELECT
    USING (EXISTS (
        SELECT 1 FROM public.post 
        WHERE post.id = comment.post_id 
        AND is_published = TRUE
    ));
  6. Write Additional Policies for Insert, Update, and Delete Actions
    Control actions such as adding or editing comments:

    sql
    CREATE POLICY "Insert comments on visible posts" 
    ON public.comment
    FOR INSERT
    USING (
        EXISTS (SELECT 1 FROM public.post 
        WHERE post.id = comment.post_id 
        AND is_published = TRUE) 
        AND auth.uid() = comment.user_id
    );

Details on Writing RLS Policies

Defining RLS policies requires familiarity with SQL conditions to ensure secure and efficient rules:

  • Where Clauses: Policies use SQL conditions akin to WHERE clauses to filter rows during operations.
  • auth.uid: This function returns the current authenticated user’s ID. It's essential for user-specific filtering.
  • Multiple Operations: Use SELECT, INSERT, UPDATE, and DELETE to control access for different actions.
  • Cross-Table Conditions: Use subqueries to check conditions in related tables. For example, ensure a comment belongs to a post the user can view.

Verifying Policy Behavior

To confirm your RLS setup works as intended, it’s vital to test your policies for all relevant scenarios.

steps

  1. Test Data Visibility
    Verify that rows are only accessible to the intended users:

    bash
    curl -H "Authorization: Bearer VALID_USER_TOKEN" \
    https://your-project.supabase.co/rest/v1/post

    Confirm unauthorized users cannot access private rows.

  2. Verify Insert and Update Constraints
    Test adding rows to ensure user identity matches:

    bash
    curl -X POST -H "Authorization: Bearer VALID_USER_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{"title": "New Post", "user_id": "wrong_user_id"}' \
    https://your-project.supabase.co/rest/v1/post

    Expect failure if the user_id doesn’t match.

  3. Check Deletion Rules
    Validate delete permissions ensure only row owners or moderators can perform deletions:

    bash
    curl -X DELETE -H "Authorization: Bearer INVALID_USER_TOKEN" \
    'https://your-project.supabase.co/rest/v1/post?id=1'

    Confirm rows remain intact.

  4. Handle Complex Relationships
    For nested tables (e.g., comments under posts), test whether access aligns with related table permissions. Use queries or API requests to check for unintended entries.

FAQ

What happens if a table’s RLS is disabled?

Without RLS enabled, all rows in the table are world-readable to clients using the anon key.

Can I test RLS locally without deploying?

Yes, you can use the Supabase SQL editor for policy testing directly in your development environment.

How do I chain multiple conditions in a policy?

Use SQL logical operators like AND and OR to combine conditions for more complex policy logic.


Official reference: Supabase documentation.