Supabase and RBAC

How to implement supabase and RBAC in refine?
12 Replies
kapa.ai
kapa.ai7mo ago
Hi @Alka. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- To implement Supabase and Role-Based Access Control (RBAC) in Refine, you need to follow these steps: 1. Set up Supabase: First, sign up with Supabase (https://app.supabase.com/) and create a PostgreSQL server. After that, create the necessary tables in the database and add relationships. Get the API keys provided by Supabase for the server and set up supabaseClient inside your Refine project. You can store these credentials in a .env file and use them to update the supabaseClient.ts file created by Refine at initialization. Here is an example of how to do it:
import { createClient } from "@refinedev/supabase";

const SUPABASE_URL = import.meta.env.SUPABASE_URL ?? "";
const SUPABASE_KEY = import.meta.env.SUPABASE_KEY ?? "";

export const supabaseClient = createClient(SUPABASE_URL, SUPABASE_KEY);
import { createClient } from "@refinedev/supabase";

const SUPABASE_URL = import.meta.env.SUPABASE_URL ?? "";
const SUPABASE_KEY = import.meta.env.SUPABASE_KEY ?? "";

export const supabaseClient = createClient(SUPABASE_URL, SUPABASE_KEY);
2. Implement RBAC: In Refine, user roles are fetched by authProvider's getPermissions() method. It is already defined for us by @refinedev/supabase. Here is an example of how it looks:
getPermissions: async () => {
const user = await supabaseClient.auth.getUser();

if (user) {
return user.data.user?.role;
}

return null;
};
getPermissions: async () => {
const user = await supabaseClient.auth.getUser();

if (user) {
return user.data.user?.role;
}

return null;
};
However, Supabase does not support setting user roles to users in the auth.users table. So, before you can use the getPermissions() method, you have to set up custom user roles. One way to implement this is with Supabase Custom Claims (https://github.com/supabase-community/supabase-custom-claims). For more detailed information, you can refer to the Refine documentation (https://refine.dev/docs/data/packages/supabase#introduction) and Refine blog posts (https://refine.dev/blog/refine-pixels-6#user-permissions-with-supabase-in-refine). ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai7mo ago
<@337909876703625216> kapa.ai is still learning and improving, please let us know how it did by reacting below
distinguished-silver
distinguished-silver7mo ago
Do i still need a casbin cerbos? @kapa.ai
kapa.ai
kapa.ai7mo ago
Let me check the knowledge base for you. One moment! :books: ---------------------- Whether you need Casbin or Cerbos for your Refine project depends on your specific access control requirements. Casbin and Cerbos are powerful libraries for implementing Access Control. They provide sophisticated solutions for managing access control throughout your application. If your project requires complex access control logic, such as Attribute-Based Access Control (ABAC), Role-Based Access Control (RBAC), or Access Control Lists (ACLs), then using Casbin or Cerbos could be beneficial. They can help you manage and enforce your access control policies in a more structured and maintainable way. Refine provides easy integrations with both Casbin and Cerbos. You can use them to define the can method of the accessControlProvider provider in Refine. Here's an example of how to use Cerbos in Refine:
<Refine
accessControlProvider={{
can: async ({ action, params, resource }) => {
const cerbosPayload = {
principal: {
id: "demoUser", // Fake a user ID
roles: [role],
attr: {},
},
resource: {
kind: resource,
instances: {
[params?.id || "new"]: {
attr: params,
},
},
},
actions: [action],
};
const result = await cerbos.check(cerbosPayload);
return Promise.resolve({
can: result.isAuthorized(params?.id || "new", action),
});
},
}}
/>
<Refine
accessControlProvider={{
can: async ({ action, params, resource }) => {
const cerbosPayload = {
principal: {
id: "demoUser", // Fake a user ID
roles: [role],
attr: {},
},
resource: {
kind: resource,
instances: {
[params?.id || "new"]: {
attr: params,
},
},
},
actions: [action],
};
const result = await cerbos.check(cerbosPayload);
return Promise.resolve({
can: result.isAuthorized(params?.id || "new", action),
});
},
}}
/>
However, if your project's access control requirements are simple and can be handled by just checking user roles, then you might not need Casbin or Cerbos. You can simply use the getPermissions() method of the authProvider to fetch user roles and implement access control based on those roles. For more information, you can refer to the Refine documentation (https://refine.dev/docs/guides-concepts/authentication#ui-integrations) and Refine blog posts (https://refine.dev/blog/refine-react-ant-design-admin-panel-framework#add-access-control-to-your-project-with-refine). ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai7mo ago
<@337909876703625216> kapa.ai is still learning and improving, please let us know how it did by reacting below
distinguished-silver
distinguished-silver7mo ago
If i need to have a custom role for the crud operation permission i think i will need cerbos or casbin @kapa.ai
kapa.ai
kapa.ai7mo ago
Let me check the knowledge base for you. One moment! :books: ---------------------- Yes, if you need to have custom roles for CRUD operation permissions, using Casbin or Cerbos would be beneficial. They provide a structured way to define and enforce complex access control policies. Here's an example of how you can use Casbin with Refine:
import { newEnforcer } from "casbin";
import { CanParams, CanReturnType } from "@refinedev/core";
import { adapter, model } from "../casbin/accessControl";
import { authProvider } from "./authProvider";

export const accessControlProvider = {
can: async ({ resource, action }: CanParams): Promise<CanReturnType> => {
const role = await authProvider.getPermissions?.();
const enforcer = await newEnforcer(model, adapter);
const can = await enforcer.enforce(role, resource, action);
return Promise.resolve({
can,
});
},
};
import { newEnforcer } from "casbin";
import { CanParams, CanReturnType } from "@refinedev/core";
import { adapter, model } from "../casbin/accessControl";
import { authProvider } from "./authProvider";

export const accessControlProvider = {
can: async ({ resource, action }: CanParams): Promise<CanReturnType> => {
const role = await authProvider.getPermissions?.();
const enforcer = await newEnforcer(model, adapter);
const can = await enforcer.enforce(role, resource, action);
return Promise.resolve({
can,
});
},
};
In this example, the can method of the accessControlProvider uses Casbin's enforce function to check if a user with a certain role has permission to perform a certain action on a certain resource. You can define your access control policies in Casbin's model and policy files. These policies can be as simple or as complex as you need, and can include custom roles for CRUD operations. For more information on how to use Casbin with Refine, you can refer to the Refine blog post (https://refine.dev/blog/refine-pixels-6#casbin-with-refine) and the Refine documentation (https://refine.dev/docs/authorization/access-control-provider#examples). ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai7mo ago
<@337909876703625216> kapa.ai is still learning and improving, please let us know how it did by reacting below
distinguished-silver
distinguished-silver7mo ago
But can i use supabase rls instead of using casbin or cerbos? @kapa.ai
kapa.ai
kapa.ai7mo ago
Let me check the knowledge base for you. One moment! :books: ---------------------- Yes, you can use Supabase's Row Level Security (RLS) feature instead of using Casbin or Cerbos for access control in your Refine application. Supabase RLS allows you to set fine-grained access control rules directly on your database tables. These rules can be based on the user's role or any other user attribute, and they can be used to control which rows a user can select, insert, update, or delete. To use Supabase RLS with Refine, you would need to set up your access control rules in your Supabase console, and then use the getPermissions() method of the authProvider to fetch the user's role and apply the appropriate access control rules. However, please note that while Supabase RLS is a powerful tool for implementing access control at the database level, it might not provide the same level of flexibility and control as a dedicated access control library like Casbin or Cerbos, especially for more complex access control requirements. For more information on how to use Supabase RLS, you can refer to the Supabase documentation (https://supabase.io/docs/guides/auth#row-level-security). For more information on how to use Supabase with Refine, you can refer to the Refine documentation (https://refine.dev/docs/data/packages/supabase#introduction). ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai7mo ago
<@337909876703625216> kapa.ai is still learning and improving, please let us know how it did by reacting below
conscious-sapphire
conscious-sapphire7mo ago
Hey @Alka check out the Authorization guide for info about the accessControlProvider interface https://refine.dev/docs/guides-concepts/authorization/#access-control-provider No need for cerbos or casbin actually, you can implement the can function however you want. You can also achieve this by adding custom properties to your auth tables or link users with some other tables to make access control work resource based, it depends on how you want to make the implementation actually. We have examples using cerbos and casbin but you're not tied to them in any ways.
Authorization | refine
Authorization is a key aspect of security and user experience in web applications. Whether you are building a complex enterprise-level application or a simple CRUD interface, Refine's authorization system provides the necessary infrastructure to protect your resources and ensure that users interact with your application in a secure and controlle...