GuidesSupabase

RLS Policies

This guide will help you to create and enable RLS policies in Supabase for secure row-level access control, with practical examples and migration steps for Next.js applications

Overview

Row Level Security (RLS) is a powerful feature in Supabase that controls which rows a user can access in a database table and storage. It allows developers to define granular access rules directly at the database level, ensuring that different users or roles can only interact with the rows of data they are authorized to access. RLS is particularly useful in applications where data needs to be partitioned by user or organization, allowing you to isolate data without having to handle this complexity in your application code.

Significance of RLS Policies

RLS policies are essential in applications where the frontend (client) communicates directly with the database. Supabase uses RLS policies to verify the user’s identity and apply row-level access control automatically. This ensures that users can only access or modify data they have permission to, reducing the risk of exposing sensitive data to unauthorized users.

Key benefits of RLS include:

  • Security: RLS policies ensure that users only have access to the data they are authorized to view or modify.
  • Simplified Application Code: By pushing row-level access control to the database, you reduce the need for complex permission checks in the application code.
  • Direct DB Access: When using a client-side approach where the frontend communicates directly with the database, RLS policies act as an essential layer of security by verifying user identity and applying access control.

How to Create and Enable RLS Policies

Step 1: Enable Row Level Security on the Table

RLS is disabled by default on Supabase tables. To start using it, you first need to enable it for the table on which you want to apply policies. Let’s take a profiles table as an example.

Example Table:

CREATE TABLE profiles (
  id UUID PRIMARY KEY,
  name TEXT,
  email TEXT UNIQUE,
  created_at TIMESTAMP DEFAULT NOW()
);

Enable RLS on the profiles table:

ALTER TABLE profiles ENABLE ROW LEVEL SECURITY;

Step 2: Create RLS Policies

You can now create RLS policies to control access to this table. Let’s go through how to create policies for different actions (SELECT, INSERT) using the profiles table.

Policy for SELECT

This policy allows authenticated users to select rows from the profiles table based on specific conditions. For example, the following policy ensures that users can only access their own profile data:

CREATE POLICY "users can access profiles"
ON profiles
FOR SELECT
TO authenticated
USING (
  id = auth.uid()
);

Explanation:

  • The policy is named "users can access profiles".
  • The policy applies to the SELECT operation.
  • The TO authenticated clause restricts this policy to authenticated users.
  • The USING clause contains the logic that checks whether the current row's id matches the authenticated user’s ID (auth.uid() is a built-in Supabase function that returns the current user’s UUID).
Policy for INSERT

To allow users to insert data into the profiles table, you can create an insert policy. Here’s an example policy that allows authenticated users to insert new rows in the profiles table:

CREATE POLICY "users can insert profiles"
ON profiles
FOR INSERT
TO authenticated
USING (
  auth.uid() IS NOT NULL
);

Explanation:

  • This policy is named "users can insert profiles".
  • It applies to the INSERT operation.
  • It restricts this action to authenticated users.
  • The USING clause checks that the auth.uid() is not null, meaning that only authenticated users can perform the insert operation.

Migrating RLS Policy Changes in a Next.js Application

In a Next.js application, when you implement or modify RLS policies on Supabase tables, you need to ensure that these changes are reflected both in the database schema and any migrations you may use.

Step 1: Defining Migrations

In Supabase, changes such as enabling RLS or creating policies can be tracked as migrations. For example, if you're working on local development, you can create a migration script for enabling RLS and adding policies.

Example migration script:

ALTER TABLE profiles ENABLE ROW LEVEL SECURITY;
 
CREATE POLICY "users can access profiles"
ON profiles
FOR SELECT
TO authenticated
USING (id = auth.uid());
 
CREATE POLICY "users can insert profiles"
ON profiles
FOR INSERT
TO authenticated
USING (auth.uid() IS NOT NULL);

You can integrate this script with your database migration tool or directly apply it in Supabase SQL Editor.

Step 2: Testing in Next.js

After updating the database with RLS policies, test your Next.js application to ensure the new access control works as expected. You can use Supabase’s authentication functions (supabase.auth.user()) in your Next.js code to ensure that users only interact with the data they are authorized to access.

For example, in your Next.js API route:

import { supabase } from '../utils/supabaseClient';
 
export default async function handler(req, res) {
  const user = supabase.auth.user();
  
  const { data, error } = await supabase
    .from('profiles')
    .select('*')
    .eq('id', user?.id);
 
  if (error) {
    return res.status(401).json({ error: error.message });
  }
 
  res.status(200).json(data);
}

On this page