harsh-harlequin
harsh-harlequin6mo ago

Access Control based on current users subscription

I am building an app with a subscription system and I would like to disallow the user from creating, updating and deleting when their subscription status is not "active", the subscription can be found in "api/tenants/current". How can I do that with the react router and the create button and everything, without using cerbios or something.
5 Replies
kapa.ai
kapa.ai6mo ago
Hi @BlackBearFTW. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- To implement access control based on the current user's subscription status without using Cerbos or any other external service, you can leverage Refine's Access Control Provider and CanAccess component. Here's how you can achieve this: 1. Create a Custom Access Control Provider: First, you need to create a custom access control provider that checks the user's subscription status from your API. 2. Wrap Routes with CanAccess: Use the CanAccess component to protect your routes and buttons based on the user's subscription status. Step-by-Step Implementation #### 1. Create a Custom Access Control Provider Create a custom access control provider that fetches the subscription status from your API and determines if the user can perform certain actions.
// src/accessControlProvider.js
import axios from "axios";

const accessControlProvider = {
can: async ({ action, resource }) => {
try {
const response = await axios.get("/api/tenants/current");
const subscriptionStatus = response.data.subscriptionStatus;

if (subscriptionStatus !== "active") {
if (["create", "update", "delete"].includes(action)) {
return { can: false };
}
}

return { can: true };
} catch (error) {
console.error("Failed to fetch subscription status", error);
return { can: false };
}
},
};

export default accessControlProvider;
// src/accessControlProvider.js
import axios from "axios";

const accessControlProvider = {
can: async ({ action, resource }) => {
try {
const response = await axios.get("/api/tenants/current");
const subscriptionStatus = response.data.subscriptionStatus;

if (subscriptionStatus !== "active") {
if (["create", "update", "delete"].includes(action)) {
return { can: false };
}
}

return { can: true };
} catch (error) {
console.error("Failed to fetch subscription status", error);
return { can: false };
}
},
};

export default accessControlProvider;
#### 2. Integrate the Access Control Provider in Your App Wrap your application with the Refine component and provide the custom access control provider. ```javascript // src/App.tsx import { Refine, Authenticated, CanAccess } from "@refinedev/core"; import dataProvider from "@refinedev/simple-rest"; import routerProvider from "@refinedev/react-router-v6"; import { BrowserRouter, Routes, Route, Outlet } from "react-router-dom"; import { AuthPage, ThemedLayoutV2 } from "@refinedev/antd"; import { PostList, PostCreate } from "pages/posts"; import { CategoryList, CategoryShow } from "pages/categories"; import accessControlProvider from "./accessControlProvider"; const App = () => { return ( <BrowserRouter> <Refine dataProvider={dataProvider} routerProvider={routerProvider} authProvider={authProvider} accessControlProvider={accessControlProvider} resources={[ { name: "posts", list: "/posts", create: "/posts/create", }, { name: "categories", list: "/categories", show: "/categories/show/:id", }, ]} > <Routes> <Route element={ <Authenticated fallback={<Outlet />}> <NavigateToResource resource="posts" /> </Authenticated> } > <Route path="/login" element={<AuthPage type="login" />} /> </Route> <Route element={ <Authenticated redirectOnFail="/login"> <ThemedLayoutV2> <Outlet /> </ThemedLayoutV2> </Authenticated> } > <Route path="posts"> <Route index element={<PostList />} /> <Route path="create" element={ <CanAccess fallback={<div>Unauthorized!</div>}> <PostCreate /> </CanAccess> } /> </Route> <Route path="categories"> <Route index element={<CategoryList />} /> <Route path="show/:id" element={<CategoryShow />} /> </Route> </Route> </Routes> </Refine> ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai6mo ago
<@490961337896402944> kapa.ai is still learning and improving, please let us know how it did by reacting below
harsh-harlequin
harsh-harlequinOP6mo ago
eh your code block is broken @kapa.ai
kapa.ai
kapa.ai6mo ago
Let me check the knowledge base for you. One moment! :books: ---------------------- To implement access control based on the current user's subscription status without using Cerbos or any other external service, you can leverage Refine's Access Control Provider and CanAccess component. Here's how you can achieve this: 1. Create a Custom Access Control Provider: First, you need to create a custom access control provider that checks the user's subscription status from your API. 2. Wrap Routes with CanAccess: Use the CanAccess component to protect your routes and buttons based on the user's subscription status. Step-by-Step Implementation #### 1. Create a Custom Access Control Provider Create a custom access control provider that fetches the subscription status from your API and determines if the user can perform certain actions.
// src/accessControlProvider.js
import axios from "axios";

const accessControlProvider = {
can: async ({ action, resource }) => {
try {
const response = await axios.get("/api/tenants/current");
const subscriptionStatus = response.data.subscriptionStatus;

if (subscriptionStatus !== "active") {
if (["create", "update", "delete"].includes(action)) {
return { can: false };
}
}

return { can: true };
} catch (error) {
console.error("Failed to fetch subscription status", error);
return { can: false };
}
},
};

export default accessControlProvider;
// src/accessControlProvider.js
import axios from "axios";

const accessControlProvider = {
can: async ({ action, resource }) => {
try {
const response = await axios.get("/api/tenants/current");
const subscriptionStatus = response.data.subscriptionStatus;

if (subscriptionStatus !== "active") {
if (["create", "update", "delete"].includes(action)) {
return { can: false };
}
}

return { can: true };
} catch (error) {
console.error("Failed to fetch subscription status", error);
return { can: false };
}
},
};

export default accessControlProvider;
#### 2. Integrate the Access Control Provider in Your App Wrap your application with the Refine component and provide the custom access control provider. ```javascript // src/App.tsx import { Refine, Authenticated, CanAccess } from "@refinedev/core"; import dataProvider from "@refinedev/simple-rest"; import routerProvider from "@refinedev/react-router-v6"; import { BrowserRouter, Routes, Route, Outlet } from "react-router-dom"; import { AuthPage, ThemedLayoutV2 } from "@refinedev/antd"; import { PostList, PostCreate } from "pages/posts"; import { CategoryList, CategoryShow } from "pages/categories"; import accessControlProvider from "./accessControlProvider"; const App = () => { return ( <BrowserRouter> <Refine dataProvider={dataProvider} routerProvider={routerProvider} authProvider={authProvider} accessControlProvider={accessControlProvider} resources={[ { name: "posts", list: "/posts", create: "/posts/create", }, { name: "categories", list: "/categories", show: "/categories/show/:id", }, ]} > <Routes> <Route element={ <Authenticated fallback={<Outlet />}> <NavigateToResource resource="posts" /> </Authenticated> } > <Route path="/login" element={<AuthPage type="login" />} /> </Route> <Route element={ <Authenticated redirectOnFail="/login"> <ThemedLayoutV2> <Outlet /> </ThemedLayoutV2> </Authenticated> } > <Route path="posts"> <Route index element={<PostList />} /> <Route path="create" element={ <CanAccess fallback={<div>Unauthorized!</div>}> <PostCreate /> </CanAccess> } /> </Route> <Route path="categories"> <Route index element={<CategoryList />} /> <Route path="show/:id" element={<CategoryShow />} /> </Route> </Route> </Routes> </Refine> ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai6mo ago
<@490961337896402944> kapa.ai is still learning and improving, please let us know how it did by reacting below