react-acl-service
v1.0.0
Published
Backend-agnostic Access Control List (ACL) system for React with role-based permissions
Downloads
89
Maintainers
Readme
react-acl-service
A backend-agnostic, type-safe Access Control List (ACL) system for React applications. Designed for real production apps with role-based permissions, route protection, and UI-level access control.
⚠️ This library controls UI visibility only. Backend APIs must always enforce authorization separately.
✨ Features
- 🔐 Role-based access control (RBAC)
- ⚡ Async permission loading from backend
- 🧠 TypeScript-first public API
- 🧩 Backend-agnostic (REST, GraphQL, RPC, etc.)
- 🚦 Route-level protection (documented, not coupled)
- 🧱 Page / module hiding
- 🎯 Button & element-level access control
- 🔄 Role switching & permission refresh
- 💾 Optional role persistence
📦 Installation
npm install react-acl-service🧠 Core Concepts
Permission Model
Permissions are evaluated using moduleKey + permissionKey pairs.
Example:
USER.CREATE
USER.VIEW
ROLE.MANAGEYour backend should return permissions in this shape:
ModulePermissionPair🚀 Quick Start
1️⃣ Wrap your app with ACLProvider
import { ACLProvider } from 'react-acl-service';
const getUser = () => ({
roleId: 1,
roleName: 'ADMIN',
});
const fetchAllPermissions = async () => [
{
moduleId: 1,
moduleKey: 'USER',
permissionId: 1,
permissionKey: 'CREATE',
},
{
moduleId: 1,
moduleKey: 'USER',
permissionId: 2,
permissionKey: 'VIEW',
},
];
const fetchRolePermissions = async (roleId: number) => [
{
moduleId: 1,
moduleKey: 'USER',
permissionId: 1,
permissionKey: 'CREATE',
},
];
function App() {
return (
<ACLProvider
getUser={getUser}
fetchAllPermissions={fetchAllPermissions}
fetchRolePermissions={fetchRolePermissions}
>
<Dashboard />
</ACLProvider>
);
}🧩 Conditional Rendering with ACLGate
Use ACLGate to show or hide UI elements.
import { ACLGate } from 'react-acl-service';
<ACLGate
moduleKey="USER"
permissionKey="CREATE"
fallback={<p>No access</p>}
>
<button>Create User</button>
</ACLGate>Behavior
- Permission granted → children rendered
- Permission denied → fallback OR hidden
🚫 Hide vs Disable Elements
🔹 Hide element completely (default)
<ACLGate moduleKey="USER" permissionKey="DELETE">
<button>Delete</button>
</ACLGate>🔹 Disable element but keep visible
import { useACL } from 'react-acl-service';
const DeleteButton = () => {
const { hasPermission } = useACL();
const allowed = hasPermission('USER', 'DELETE');
return (
<button disabled={!allowed}>
Delete
</button>
);
};🧱 Full Page / Module Hiding
Use ACL to remove entire pages or modules from UI.
Example – Sidebar Menu
<ACLGate moduleKey="USER" permissionKey="VIEW">
<NavLink to="/users">Users</NavLink>
</ACLGate>If permission is missing → menu item is not rendered at all.
🚦 Route Protection (Page-Level)
This library is router-agnostic.
Route protection is implemented in your app, using useACL.
Example (React Router)
import { Navigate } from 'react-router-dom';
import { useACL } from 'react-acl-service';
const ProtectedRoute = ({ children }) => {
const { hasPermission, loading } = useACL();
if (loading) return null;
if (!hasPermission('USER', 'VIEW')) {
return <Navigate to="/unauthorized" replace />;
}
return children;
};⚠️ Route guards are not included in the package by design.
🧭 Navigation / Tabs / Sections
Tabs Example
import { useACL } from 'react-acl-service';
const Tabs = () => {
const { hasPermission } = useACL();
return (
<>
{hasPermission('USER', 'VIEW') && <Tab label="Users" />}
{hasPermission('ROLE', 'VIEW') && <Tab label="Roles" />}
</>
);
};🪝 Using the useACL Hook
import { useACL } from 'react-acl-service';
const Dashboard = () => {
const {
currentRole,
hasPermission,
refreshPermissions,
} = useACL();
return (
<>
<p>Role: {currentRole?.name}</p>
{hasPermission('USER', 'CREATE') && (
<button>Create User</button>
)}
<button onClick={refreshPermissions}>
Refresh Permissions
</button>
</>
);
};🧠 Permission Utilities
import {
checkPermission,
checkAnyPermission,
checkAllPermissions,
} from 'react-acl-service';Any Permission Required
checkAnyPermission(permissions, [
{ moduleKey: 'USER', permissionKey: 'CREATE' },
{ moduleKey: 'USER', permissionKey: 'UPDATE' },
]);All Permissions Required
checkAllPermissions(permissions, [
{ moduleKey: 'USER', permissionKey: 'CREATE' },
{ moduleKey: 'USER', permissionKey: 'APPROVE' },
]);🧾 TypeScript Support
Exported Types
import type {
ModulePermissionPair,
ACLProviderProps,
} from 'react-acl-service';⚙️ ACLProvider Props
| Prop | Required | Description |
| ---------------------- | -------- | ---------------------------- |
| getUser | ✅ | Returns logged-in user role |
| fetchAllPermissions | ❌ | Fetches all permissions |
| fetchRolePermissions | ❌ | Fetches role permissions |
| initialPermissions | ❌ | Static permissions |
| persistRole | ❌ | Persist role in localStorage |
| storageKey | ❌ | Custom storage key |
🏗️ Recommended Architecture
Backend → returns permissions
Frontend App → passes APIs
react-acl-service → evaluates access✔ No backend coupling ✔ No routing assumptions ✔ Fully scalable
🔐 Security Note (IMPORTANT)
This library does not secure APIs. Backend must always validate permissions.
ACL is for UI visibility & UX, not enforcement.
📄 License
MIT © Anantha Lakshmi Gatta
