NestboltNestbolt

@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 PermissionRegistrarService to 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 covers articles.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, web vs. 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-emitter is 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, and user_has_permissions tables. 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:

LayerComponentsResponsibility
EntitiesPermissionEntity, RoleEntity, UserHasRolesEntity, UserHasPermissionsEntityDatabase schema and relationships via TypeORM
Low-Level ServicesPermissionService, RoleServiceCRUD operations for individual permissions and roles
RegistrarPermissionRegistrarServiceUser-facing operations: assigning/revoking roles and permissions, running authorization checks, managing the cache
Guards and DecoratorsRolesGuard, PermissionsGuard, RolesOrPermissionsGuard, @RequireRoles(), @RequirePermissions(), @RequireRolesOrPermissions()Declarative route protection
Wildcard EngineWildcardPermissionServiceTrie-based wildcard permission matching
CachePermissionCacheTTL-based in-memory cache for permission data

Database Schema

The package creates the following tables:

TablePurpose
permissionsStores permission records (id, name, guard_name, timestamps)
rolesStores role records (id, name, guard_name, timestamps)
role_has_permissionsMany-to-many join table between roles and permissions
user_has_rolesAssociates users with roles (user_id, role_id)
user_has_permissionsAssociates 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:

  1. Direct permission check -- The user's directly assigned permissions are loaded and compared against the required permission.
  2. Role-inherited permission check -- The user's roles are loaded, and each role's permissions are checked for a match.
  3. 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.