How to Implement Role-Based Access with Supabase

akkilah

Ahmad Akkilah

Posted on May 21, 2023

How to Implement Role-Based Access with Supabase

The Setup:

Before discussing the role-based aspect, let me provide an overview of the project setup. Initially, my objective was to develop an API middleware between the frontend and backend components. The main idea behind this approach was to enhance flexibility and simplify the process of migrating between different services. However, upon reflection, I must admit that I made a mistake. The API middleware I created turned out to be nothing more than a wrapper for the Supabase JavaScript SDK. If I were to rewrite it, I would opt for a solution like Prisma, which would have significantly streamlined the migration process. Nevertheless, life is a constant learning experience. Now, let me provide you with a high-level overview of the architecture:

high-level overview of the architecture

Authentication:

One of the initial challenges I encountered was obtaining a JWT token for the client (customer) to be passed with the API requests. I came across several online tutorials, but most of them were either outdated or provided incorrect information. After research, I found that the correct method for obtaining the token using Supabase is as follows:



const options = {
  db: {
    schema: 'public',
  },
  auth: {
    autoRefreshToken: true,
    persistSession: true,
    detectSessionInUrl: true,
  },
  global: {
    headers: {
    Authorization: `Bearer ${token}`,
    },
  },
};

const supabase = createClient(supabaseUrl, supabaseKey, options);



Enter fullscreen mode Exit fullscreen mode

All other suggestions I found online, such as supabase.auth.setSession() or const { user, error } = supabase.auth.setAuth(access_token), were not functioning. if it work for you I would like to know .

Creating the Role-Based System:

By default, Supabase provides three types of users: server_role, which bypasses low-level security RLS (Row-Level Security); anon, representing anonymous users; and authenticated, referring to users who are authenticated.

Supabase does not currently have built-in support for role-based access as of May 21, 2023. However, they are actively working on implementing it in the future. In the meantime, you can leverage the functionality provided by the supabase-custom-claims library. I have personally found this library effective and have successfully integrated it into my system using the SQL functions it offers.

The supabase-custom-claims library offers the following benefits for role-based access implementation:

  1. Ease of understanding: It involves creating PostgreSQL functions that can be deleted at any time.

  2. Utilizes a special colume row_app_meta_data in auth.user table which is designed for additional information by Supabase: This reduces the likelihood of future issues compared to modifying database privileges, etc.

To use this library, follow these steps:

  1. Go to the following link: Install.sql .

  2. Copy and paste the SQL script into your Supabase SQL editor and execute it (the script should run successfully).

Upon executing the script, you will create 6 Supabase functions, which can be found under "Database" -> "Function".

The six SQL functions provided by the library are:

  1. get_my_claims
  2. get_my_claim
  3. get_claims
  4. set_claim
  5. delete_claim
  6. is_claims_admin

For our use case, the most important function is set_claim.To use it, execute the following SQL statement in the Supabase SQL editor:



set_claim(uid uuid, claim text, value jsonb);


Enter fullscreen mode Exit fullscreen mode
  • uid: Provide the user UUID to whom you want to assign the role.
  • claim: Set it as 'userrole'.
  • value: Specify the role you want to assign.

For example:



set_claim('03acaa13-7989-45c1-8dfb-6eeb7cf0b92e', 'userrole', '"webadmin"');


Enter fullscreen mode Exit fullscreen mode

Applying the Role-Based System:

By default, Supabase provides three types of users: server_role, which bypasses low-level security RLS (Row-Level Security); anon, representing anonymous users; and authenticated, referring to users who are authenticated.

If you want to implement role-based access in your system, Supabase does not yet provide built-in functionality for that as of May 21, 2023. However, they appear to be working towards implementing it soon. In the meantime, you can utilize a method I found effective and implemented in my system using the 4vsql function provided by the supabase-custom-claims library.

The supabase-custom-claims library offers the following benefits for role-based access implementation:

  1. Ease of understanding: It involves creating PostgreSQL functions that can be deleted at any time.
  2. Utilizes a special column row_app_meta_data which is designed for additional information by Supabase: This reduces the likelihood of future issues compared to modifying database privileges, etc.

To use this library, follow these steps:

  1. Go to the following link: https://github.com/supabase-community/supabase-custom-claims/blob/main/install.sql.
  2. Copy and paste the SQL script into your Supabase SQL editor and execute it (the script should run successfully).

Upon executing the script, you will create 6 Supabase functions, which can be found under "Database" -> "Function".

The six SQL functions provided by the library are:

get_my_claims
get_my_claim
get_claims
set_claim
delete_claim
is_claims_admin
Enter fullscreen mode Exit fullscreen mode

For our use case, the most important function is set_claim.To use it, execute the following SQL statement in the Supabase SQL editor:

set_claim(uid uuid, claim text, value jsonb);

  • uid: Provide the user UUID to whom you want to assign the role.
  • claim: Set it as 'userrole'.
  • value: Specify the role you want to assign.

For example:

select set_claim('72e699aa-d50c-4ee3-9eb6-e29c169b5eff', 'userrole', '"webadmin"');

You can add any role you want to check for later in RLS.

let's see how to check for the role in RLS.

In the Supabase UI:

In the Supabase UI adding RLS Role

  • Policy name: Choose any name.
  • Target roles: Set it as 'authenticated'.
  • USING expression: get_my_claim('userrole') = '"webadmin"'.

Note the double quotes before the single quote; they are important.
WITH CHECK expression: get_my_claim('userrole') = '"webadmin"'.

With this setup, the system will check for the role, and if it evaluates to true, it will allow access; otherwise, it will reject it.

💖 💪 🙅 🚩
akkilah
Ahmad Akkilah

Posted on May 21, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related