xenial-black
xenial-black8mo ago

Proper way to use AuthProvider with Supabase

Hello, I’m new with Refine and I’m just playing with the AuthProvider and Supabase. I think I could make it working just like the tutorial https://refine.dev/blog/refine-pixels-6/#refineweek-series But I have a couple of question: I notice that getPermission is called a lot and is hitting the database constantly. Is there a way to get the role directly from the …auth-token in localstorage? It’t safe to save the role in a custom localstorage? Something like the example https://refine.dev/docs/authentication/auth-provider/#getpermissions. For example the user could change it manually and get any permission, maybe this need additional work with RLS validation from the Supabse side? And another thing with the Pixels 6 tutorial, is that while getPermission is calling, the buttons are enabled and the user can click on them. Just after the response in getPermission the buttons are disabled. Thanks
Auth Provider | Refine
Auth provider is an object that contains methods to handle authentication and access control in your app by having Refine consume them. These methods expect to return a promise, so they can be used with async methods.
Implementing Role Based Access Control | Refine
We'll implement Role Based Access Control (RBAC)
2 Replies
kapa.ai
kapa.ai8mo ago
Hi @RAFA3L. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- To properly use AuthProvider with Supabase in Refine, you can follow the steps outlined in the provided knowledge sources. Here are the key points and solutions to your questions: 1. Reducing Database Hits for getPermissions To avoid hitting the database constantly, you can store the user's role in localStorage after the initial fetch. However, storing sensitive information like roles in localStorage can be risky because users can manipulate it. To mitigate this, you should combine this approach with server-side validation using Supabase's Row Level Security (RLS). Here's an example of how you can modify the getPermissions method to use localStorage:
import { AuthProvider } from "@refinedev/core";
import { supabaseClient } from "../utility";

export const authProvider: AuthProvider = {
getPermissions: async () => {
try {
// Check if role is already stored in localStorage
const storedRole = localStorage.getItem("userRole");
if (storedRole) {
return storedRole;
}

// Fetch role from Supabase if not in localStorage
const { data, error } = await supabaseClient.auth.getUser();
if (error) {
console.error(error);
return;
}

const { data: roleData } = await supabaseClient.rpc("get_my_claim", {
claim: "role",
});

// Store role in localStorage
if (roleData) {
localStorage.setItem("userRole", roleData);
}

return roleData;
} catch (error: any) {
console.error(error);
return;
}
},
// Other methods...
};
import { AuthProvider } from "@refinedev/core";
import { supabaseClient } from "../utility";

export const authProvider: AuthProvider = {
getPermissions: async () => {
try {
// Check if role is already stored in localStorage
const storedRole = localStorage.getItem("userRole");
if (storedRole) {
return storedRole;
}

// Fetch role from Supabase if not in localStorage
const { data, error } = await supabaseClient.auth.getUser();
if (error) {
console.error(error);
return;
}

const { data: roleData } = await supabaseClient.rpc("get_my_claim", {
claim: "role",
});

// Store role in localStorage
if (roleData) {
localStorage.setItem("userRole", roleData);
}

return roleData;
} catch (error: any) {
console.error(error);
return;
}
},
// Other methods...
};
2. Handling Button States While getPermissions is Loading To handle the state of buttons while getPermissions is being called, you can use the usePermissions hook provided by Refine. This hook allows you to check the user's permissions and update the UI accordingly. Here's an example of how you can use the usePermissions hook:
import { usePermissions } from "@refinedev/core";
import { DeleteButton } from "@refinedev/antd";

const MyComponent = () => {
const { data: permissions, isLoading } = usePermissions();

return (
<div>
<DeleteButton disabled={isLoading || !permissions?.includes("admin")} />
</div>
);
};
import { usePermissions } from "@refinedev/core";
import { DeleteButton } from "@refinedev/antd";

const MyComponent = () => {
const { data: permissions, isLoading } = usePermissions();

return (
<div>
<DeleteButton disabled={isLoading || !permissions?.includes("admin")} />
</div>
);
};
In this example, the DeleteButton will be disabled while the permissions are being fetched (isLoading is true) or if the user does not have the required permissions. Additional Considerations - Security: Always ensure that sensitive information is validated on the server side. Even if you store roles in localStorage for performance reasons, you should enforce permissions and roles using Supabase's RLS policies to prevent unauthorized access. - Performance: Caching roles in localStorage can improve performance, but make sure to handle cases where roles might change and need to be refreshed. For more detailed information, you can refer to the Auth Provider documentation (https://refine.dev/docs/authentication/auth-provider/#getpermissions) and the accessControlProvider documentation (https://refine.dev/docs/authorization/access-control-provider/). If you have further questions or need more specific examples, feel free to ask! ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai8mo ago
<@455754342981566465> kapa.ai is still learning and improving, please let us know how it did by reacting below

Did you find this page helpful?