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
- Node.js installed
- An initialized Supabase project with a created user
- An Oso account
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.
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.
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.
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.
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.