Supabase.PostgREST.RLS (supabase_postgrest v1.2.2)

View Source

Helpers for working with PostgreSQL Row Level Security (RLS) policies in Ecto.

This module provides utilities to set session context for RLS policies when using the Ecto schemas generated by mix supabase.gen.schema.

Usage

Wrap operations in a transaction and set session variables that are automatically cleaned up when the transaction completes:

defmodule MyApp.Repo do
  use Ecto.Repo, otp_app: :my_app

  import Supabase.PostgREST.RLS

  def with_user_context(user_id, fun) do
    transaction(fn ->
      set_rls_context(__MODULE__, "request.jwt.claims.sub", user_id)
      fun.()
    end)
  end
end

# Usage
MyApp.Repo.with_user_context(user_id, fn ->
  MyApp.Repo.all(MyApp.Accounts.User)
end)

Common Supabase RLS Patterns

Supabase RLS policies commonly use these session variables:

  • request.jwt.claims.sub - User ID from JWT
  • request.jwt.claims.role - User role from JWT
  • request.jwt.claims.email - User email from JWT

Example policy in your database:

CREATE POLICY "Users can view their own data"
  ON users FOR SELECT
  USING (id = current_setting('request.jwt.claims.sub')::uuid);

Testing with RLS

When testing, you may want to bypass RLS policies. You can disable RLS for specific tables:

Ecto.Adapters.SQL.query!(MyApp.Repo, "ALTER TABLE users DISABLE ROW LEVEL SECURITY")

Summary

Functions

Gets the current value of an RLS context variable.

Sets multiple RLS context variables at once in a single database query.

Sets a PostgreSQL session configuration variable for the current transaction.

Functions

get_rls_context(repo, key)

Gets the current value of an RLS context variable.

Returns nil if the variable is not set.

Examples

current_user_id = get_rls_context(MyApp.Repo, "request.jwt.claims.sub")

set_rls_claims(repo, claims)

Sets multiple RLS context variables at once in a single database query.

This is more efficient than calling set_rls_context/3 multiple times when you need to set several session variables.

Parameters

  • repo - The Ecto repository module
  • claims - A map of configuration keys to values

Examples

# Set multiple JWT claims at once
Repo.transaction(fn ->
  set_rls_claims(repo, %{
    "request.jwt.claims.sub" => user.id,
    "request.jwt.claims.role" => "authenticated",
    "request.jwt.claims.email" => user.email
  })
  Repo.all(User)
end)

set_rls_context(repo, key, value)

Sets a PostgreSQL session configuration variable for the current transaction.

This function executes set_config/3 with the is_local parameter set to true, ensuring the configuration is transaction-scoped and automatically cleared when the transaction completes.

Parameters

  • repo - The Ecto repository module
  • key - The configuration parameter name (e.g., "request.jwt.claims.sub")
  • value - The value to set (will be converted to string)

Examples

# Setting user ID for RLS policies
Repo.transaction(fn ->
  set_rls_context(repo, "request.jwt.claims.sub", user.id)
  Repo.all(User)
end)

# Setting user role
Repo.transaction(fn ->
  set_rls_context(repo, "request.jwt.claims.role", "authenticated")
  Repo.all(User)
end)

# Setting user email
Repo.transaction(fn ->
  set_rls_context(repo, "request.jwt.claims.email", user.email)
  Repo.all(User)
end)

# With custom variable name for multi-tenancy
Repo.transaction(fn ->
  set_rls_context(repo, "app.current_tenant", tenant_id)
  Repo.all(from u in User, where: ...)
end)

Security Considerations

  • Always validate and sanitize the value parameter before passing it to this function
  • Never pass user input directly without validation
  • Consider using prepared statements for complex values