@nestbolt/permissions
Introduction
Role-Based Access Control (RBAC) system for NestJS with TypeORM support, caching, wildcard permissions, and lifecycle events.
Overview
@nestbolt/permissions is a Role-Based Access Control (RBAC) package for NestJS applications backed by TypeORM. It provides a complete system for defining roles and permissions, assigning them to users, protecting routes with guards, and checking authorization programmatically.
RBAC is an authorization model in which access decisions are based on the roles a user holds. Each role is associated with a set of permissions, and users inherit the permissions of their assigned roles. Users can also receive direct permissions that are not tied to any role.
Key Features
- Roles and Permissions -- Create named roles and fine-grained permissions, then associate permissions with roles. Users can be assigned any number of roles and direct permissions.
- Route Guards -- Protect controller routes declaratively using
@RequireRoles(),@RequirePermissions(), and@RequireRolesOrPermissions()decorators paired with the corresponding NestJS guards. - Programmatic Checks -- Use
PermissionRegistrarServiceto assign, revoke, sync, and check roles and permissions in your application logic. - Wildcard Permissions -- Optionally enable wildcard matching so that a permission like
articles.*automatically coversarticles.create,articles.edit,articles.delete, and any other sub-permission. A single*permission grants access to everything. - Guard Scoping -- Scope roles and permissions to a named guard (defaults to
"default"), allowing you to maintain separate permission sets for different authentication contexts (for example,webvs.api). - In-Memory Caching -- An optional in-memory cache (enabled by default, 24-hour TTL) reduces database queries. The cache is automatically flushed whenever roles or permissions change.
- Lifecycle Events -- When
@nestjs/event-emitteris installed, the package emits events for role/permission creation, deletion, attachment, detachment, and cache flushes, making it easy to build audit trails or trigger side effects. - TypeORM Entities Included -- Ships with ready-to-use TypeORM entities for the
permissions,roles,role_has_permissions,user_has_roles, anduser_has_permissionstables. Just register the module and run your migrations. - Global Module -- The module registers globally, so you only import it once in your root
AppModule.
Architecture
The package is organized around three service layers and a guard layer:
| Layer | Components | Responsibility |
|---|---|---|
| Entities | PermissionEntity, RoleEntity, UserHasRolesEntity, UserHasPermissionsEntity | Database schema and relationships via TypeORM |
| Low-Level Services | PermissionService, RoleService | CRUD operations for individual permissions and roles |
| Registrar | PermissionRegistrarService | User-facing operations: assigning/revoking roles and permissions, running authorization checks, managing the cache |
| Guards and Decorators | RolesGuard, PermissionsGuard, RolesOrPermissionsGuard, @RequireRoles(), @RequirePermissions(), @RequireRolesOrPermissions() | Declarative route protection |
| Wildcard Engine | WildcardPermissionService | Trie-based wildcard permission matching |
| Cache | PermissionCache | TTL-based in-memory cache for permission data |
Database Schema
The package creates the following tables:
| Table | Purpose |
|---|---|
permissions | Stores permission records (id, name, guard_name, timestamps) |
roles | Stores role records (id, name, guard_name, timestamps) |
role_has_permissions | Many-to-many join table between roles and permissions |
user_has_roles | Associates users with roles (user_id, role_id) |
user_has_permissions | Associates users with direct permissions (user_id, permission_id) |
Both permissions and roles have a unique constraint on (name, guard_name), ensuring no duplicates within the same guard scope.
How Authorization Checks Work
When a guard checks whether a user has a given permission, the following steps are performed in order:
- Direct permission check -- The user's directly assigned permissions are loaded and compared against the required permission.
- Role-inherited permission check -- The user's roles are loaded, and each role's permissions are checked for a match.
- Wildcard check (if enabled) -- All of the user's permissions (direct and role-inherited) are compiled into a trie index, and the required permission is tested against the wildcard patterns.
If any step produces a match, access is granted. If none match, a ForbiddenException is thrown.
Next Steps
- Installation -- Install the package and its peer dependencies.
- Quick Start -- Set up the module, create roles and permissions, and protect your first route.
- Configuration -- Learn about all available module options.