Dejan Lukić

Oso + Supabase

Originally written for Oso.

Supabase, an open-source backend-as-a-service (BaaS) platform, has seen rapid adoption as a full-fledged competitor to Firebase. Being open-source and detached from Google allows users to use Supabase more flexibly than Firebase.

By default, Supabase uses PostgreSQL’s Row-level security, a feature enabling users to define table policies such that it can control data manipulation on a per-user basis.

With that, Supabase doesn’t support Role-Based Access Control (RBAC) or Attribute-Based Access Control (ABAC).

RBAC is a system that manages and enforces user permissions based on their assigned roles within an organization. It ensures that users can only access resources and perform actions relevant to specific roles.

ABAC is a similar system that enforces user permissions based on attributes, such as user characteristics, resource properties, and environmental conditions, allowing for more fine-grained control over access.

To implement RBAC or ABAC with Supabase in this guide, you will use Oso - a batteries-included authorization-as-a-service (AaaS) provider.

Prerequisites

Setting Up the Project

Head over to your terminal and install the necessary dependencies:

$ npm i --save-dev oso-cloud @supabase/supabase-js

Create a new file index.js which will serve as the main file in the project.

Continue by importing the dependencies:

import { createClient } from '@supabase/supabase-js';
import { Oso } from 'oso-cloud';

Next, add Oso and Supabase authentication key, as well as the Supabase’s project URL:

const supabaseUrl = '';
const supabaseKey = '';
const osoApiKey = '';

Note: These should be read from the environment variables. For that instance use the dotenv package.

Now, initialize the Oso and Supabase clients:

const supabase = createClient(supabaseUrl, supabaseKey);
const oso = new Oso('https://cloud.osohq.com', osoApiKey);

Setting Up Oso Rules

Now, you will set up Oso Rules that will dictate which role will allow certain action on some arbitrary resource.

Navigate to the Oso Rules Editor. You will be presented with the Workbench mode, allowing you for a more visual approach.

Oso Rules Editor

In the top section, it should say Add a resource. Next to the dropdown, enter the Resource name Post. Press the + button on the right side to create a new resource.

You will be presented with a new resource, showcasing its permissions and rules. To keep it simple, stick with this and hit Deploy in the top-right corner.

New resource in Oso Rules Editor

Installing Supabase Custom Claims

Supabase originally doesn’t allow custom user roles nor its mutation. To create custom user roles you will need to use Supabase Custom Claims.

Custom Claims will just add a JSON data to the user’s access token supplied by Supabase’s session.

First, copy the whole file content from the install.sql. Next, navigate to the SQL Editor of your project.

Create a new query and paste the file contents inside.

Supabase SQL Editor

Press Run or hit (Command + Enter or Control + Enter). Upon completion you should see Success. No rows returned message in the console.

Setting a Custom Role to a User

From the sidebar, choose Authentication. Inside of it, press Users. You will be presented with a list of users. Choose a user whom you’d like to create a custom role, and copy its User UID.

Supabase Authentication Settings

Navigate back to the SQL Editor and run the following command:

select set_claim('<User UID>', 'permission', '"edit"')

Replace the <User UID> with your exact User UID. This will assign edit permission to the given user.

Using Oso with Supabase in Node.js

After setting up the Supabase claims and Oso rules, you’re now ready to implement this in Node.js.

For this example, you will use an arbitrary table posts from which we will fetch data.

Start with creating a method that will fetch data from the table.

const fetchPosts = async (session) => {
	try {
		const { data: posts, error } = await supabase
			.from('posts')
			.select('*');
       return posts;
	} catch (e) {
		console.log(e);
	}
};

By calling this method, you will get all the posts from the table.

Now, you will filter those posts and return only those that should be viewed by a user with “edit” permission.

const fetchPosts = async (session) => {
	const email = session.user.email;
	const permission = session.user.app_metadata.permision;
	try {
		const { data: posts, error } = await supabase.from('posts').select('*');
		const authorizedPosts = posts.filter((post) => {
			try {
				// Enforce the authorization rules using Oso
				if (oso.authorize(email, String(permission), 'Post')) return true;
			} catch (e) {
				return false; // The user is not authorized to read this post
			}
		});
		console.log(authorizedPosts);
	} catch (e) {
		console.log(e);
	}
};

Testing the Rules

To test the rules, you should be logged in with Supabase, which will enable you to view the user’s session. The user’s session should be passed to the fetchPosts method.

A very crude example would be the following with Supabase’s Login With Email:

const login = async () => {
	const { data, error } = await supabase.auth.signInWithPassword({
		email: 'foo@bar.xyz',
		password: '1234',
	});
  fetchPosts(data.session);
};

Calling the login method will output all posts the user is able to view.

Note: RLS policies must be disabled on the table.

Next Steps and Resources

Learn more about Oso in the blog and Cloud Documentation. Supabase Docs are also a great source of vast information about Supabase’s almost endless features.

To digest more about RBAC, read through Multitenant roles.

If you have any questions, or just want to talk something through, jump into Slack. An Oso engineer or one of the thousands of developers in the growing community will be happy to help.

You can also hop on a 1:1 call with an Oso engineer.

Conclusion

In this guide you learned how to utilize two of most powerful players in their fields - Oso and Supabase. Covering the project setup and testing.

Using Supabase Custom Claims and Oso, you successfully created a simple authorization solution.

Even though Supabase is super flexible and flooded with features, it lacks some authorization features like RBAC and ABAC.

Oso is used and trusted by major players like Visa, Verizon and Intercom that opt for AaaS providers in their complex infrastructures.

#databases #guide #oso #supabase