@haykal/rbac-backend
v1.0.0
Published
> Role-Based Access Control with hierarchy, permission caching, guard decorators, and configurable role seeding.
Readme
@haykal/rbac-backend
Role-Based Access Control with hierarchy, permission caching, guard decorators, and configurable role seeding.
Installation
pnpm add @haykal/rbac-backendConfiguration
forRoot() Options
import { RbacModule } from '@haykal/rbac-backend';
@Module({
imports: [
RbacModule.forRoot({
defaultRoles: [
{
name: 'admin',
displayName: 'Administrator',
permissions: ['*'],
isSystem: true,
},
{
name: 'user',
displayName: 'Regular User',
permissions: ['profile.read', 'profile.update'],
isSystem: true,
isDefault: true,
},
],
superAdminRole: 'superadmin',
permissionCacheTtlSeconds: 300,
}),
],
})
export class AppModule {}| Property | Type | Default | Description |
| --------------------------- | ------------------ | -------------- | --------------------------------------------- |
| defaultRoles | RoleDefinition[] | [] | Roles to seed on startup |
| superAdminRole | string | 'superadmin' | Role name that bypasses all permission checks |
| permissionCacheTtlSeconds | number | 300 | Redis cache TTL for user permissions |
RoleDefinition:
| Property | Type | Description |
| ------------- | ---------- | ------------------------------------- |
| name | string | Unique role identifier |
| displayName | string | Human-readable name |
| description | string? | Optional description |
| permissions | string[] | Permission keys (['*'] = all) |
| isSystem | boolean? | Cannot be modified/deleted |
| isDefault | boolean? | Auto-assigned to new users |
| parentRole | string? | Parent role for hierarchy/inheritance |
Key Exports
| Export | Type | Description |
| ----------------------- | ------------- | ----------------------------------------------------------- |
| RbacModule | NestJS Module | Main module with forRoot() / forRootAsync() |
| RBAC_CONFIG | Symbol | Inject the config object |
| RbacService | Service | Full RBAC management (roles, permissions, user assignments) |
| PermissionsGuard | Guard | Check route-level permission requirements |
| RolesGuard | Guard | Check route-level role requirements |
| @RequirePermissions() | Decorator | Declare permission requirements on a route |
| @RequireRoles() | Decorator | Declare role requirements on a route |
| RBAC_ENTITIES | Array | Entities for migration discovery |
Entities
| Entity | Table | Description |
| ---------------------- | ----------------------- | ------------------------------------ |
| RoleEntity | rbac_roles | Role definitions with hierarchy |
| PermissionEntity | rbac_permissions | Permission definitions with grouping |
| RolePermissionEntity | rbac_role_permissions | Role-to-permission join table |
| UserRoleEntity | rbac_user_roles | User-to-role assignments with audit |
Domain Errors
| Error | Code | Status | Description |
| ------------------------------ | --------------------------------- | ------ | ------------------------- |
| RoleNotFoundError | RBAC_ROLE_NOT_FOUND | 404 | Role not found |
| RoleAlreadyExistsError | RBAC_ROLE_ALREADY_EXISTS | 409 | Duplicate role name |
| SystemRoleError | RBAC_SYSTEM_ROLE_IMMUTABLE | 403 | Cannot modify system role |
| PermissionNotFoundError | RBAC_PERMISSION_NOT_FOUND | 404 | Permission not found |
| InsufficientPermissionsError | RBAC_INSUFFICIENT_PERMISSIONS | 403 | Missing permissions |
| InsufficientRolesError | RBAC_INSUFFICIENT_ROLES | 403 | Missing roles |
| CircularRoleHierarchyError | RBAC_CIRCULAR_HIERARCHY | 422 | Circular parent chain |
| UserRoleAlreadyAssignedError | RBAC_USER_ROLE_ALREADY_ASSIGNED | 409 | Duplicate role assignment |
Domain Events
| Event | Payload |
| ----------------------------- | -------------------------------------------------------------- |
| RoleCreatedEvent | roleId, roleName |
| RoleUpdatedEvent | roleId, roleName, changes |
| RoleDeletedEvent | roleId, roleName |
| RolePermissionsChangedEvent | roleId, roleName, addedPermissions, removedPermissions |
| UserRoleAssignedEvent | userId, roleId, roleName, assignedBy |
| UserRoleRemovedEvent | userId, roleId, roleName |
API Endpoints
All endpoints require JWT authentication. Grouped under /api/rbac.
Roles (/rbac/roles)
| Method | Path | Description |
| -------- | ----------------------------- | ---------------------------------- |
| GET | /rbac/roles | List all roles |
| POST | /rbac/roles | Create a new role |
| GET | /rbac/roles/:id | Get role details |
| PATCH | /rbac/roles/:id | Update a role |
| DELETE | /rbac/roles/:id | Delete a non-system role |
| GET | /rbac/roles/:id/permissions | Get role permissions |
| PUT | /rbac/roles/:id/permissions | Set role permissions (replace all) |
| POST | /rbac/roles/:id/permissions | Add permissions to role |
| DELETE | /rbac/roles/:id/permissions | Remove permissions from role |
Permissions (/rbac/permissions)
| Method | Path | Description |
| ------ | ------------------- | -------------------------------------------------- |
| GET | /rbac/permissions | List all permissions (?grouped=true for grouped) |
User Roles (/rbac/users)
| Method | Path | Description |
| -------- | ----------------------------------- | ------------------------------ |
| GET | /rbac/users/:userId/roles | Get user's roles |
| PUT | /rbac/users/:userId/roles | Set user's roles (replace all) |
| POST | /rbac/users/:userId/roles | Add role(s) to user |
| DELETE | /rbac/users/:userId/roles/:roleId | Remove role from user |
My RBAC (/rbac/me)
| Method | Path | Description |
| ------ | ---------------------- | -------------------------------------------- |
| GET | /rbac/me/permissions | Current user's effective permissions |
| GET | /rbac/me/roles | Current user's roles |
| GET | /rbac/me/check | Check permissions (?permissions=key1,key2) |
Usage Examples
Protecting Routes with Permissions
import { RequirePermissions, RequireRoles } from '@haykal/rbac-backend';
@Controller('orders')
export class OrdersController {
@RequirePermissions('orders.create')
@Post()
async create() {
/* ... */
}
@RequireRoles('admin')
@Delete(':id')
async delete() {
/* ... */
}
}Registering Domain Permissions
import { RbacService } from '@haykal/rbac-backend';
@Module({})
export class OrdersModule implements OnModuleInit {
constructor(private rbacService: RbacService) {}
async onModuleInit() {
await this.rbacService.registerPermissions([
{ key: 'orders.create', displayName: 'Create Orders', group: 'orders' },
{ key: 'orders.read', displayName: 'Read Orders', group: 'orders' },
{ key: 'orders.update', displayName: 'Update Orders', group: 'orders' },
{ key: 'orders.delete', displayName: 'Delete Orders', group: 'orders' },
]);
}
}Related Packages
@haykal/rbac-client— React Query hooks for RBAC@haykal/auth-backend— JWT auth (RBAC guards layer on top)@haykal/core-backend— Base infrastructure
Further Reading
- API Reference — Full endpoint listing
- Architecture Overview — System design and module composition
- Backend Style Guide — Coding conventions
