node-rbac-kit
Enterprise-Grade Role-Based Access Control (RBAC) Engine for Node.js.
node-rbac-kit is a fast, framework-agnostic, TypeScript-first authorization library. It supports hierarchical roles, dynamic context rules, wildcards, multi-tenant SaaS applications, validation, graph export, and caching (In-Memory and Redis) with native adapters for Express and NestJS.
Features
- Core RBAC: Declarative role and permission maps.
- Hierarchical Inheritance: Graph-based role resolution with cycle detection.
- Wildcard Matchers: Glob-like namespace permissions (e.g.,
loan.*matchesloan.approveandloan.create). - Dynamic Rules (ABAC): Context-aware authorization (e.g., loan officer can approve only if user and loan branches match).
- Multi-Tenant SaaS: Complete role, rule, and cache isolation between tenants out of the box.
- Diagnostics & Explanations: Returns detailed denial reasons, required roles, and missing permissions instead of simple booleans.
- High-Performance Cache: Memory and Redis caching adapters with automatic invalidation.
- Visual Graph Exporter: Generate permission graphs/trees for auditing or dashboard UI.
- Diagnostic Validator: Detect duplicate permissions, unused permissions, circular paths, and missing parent roles.
- Framework Integrations: Custom NestJS Decorators/Guards and Express middleware.
Installation
npm install node-rbac-kitQuick Start
import { PermissionEngine, MemoryCacheAdapter } from 'node-rbac-kit';
// 1. Initialize Engine
const engine = new PermissionEngine({
cache: new MemoryCacheAdapter(300), // cache results for 5 mins
auditLogger: (event) => {
console.log(`[RBAC AUDIT] ${event.type} - User: ${event.userId} - Action: ${event.action} - Decision: ${event.decision}`);
}
});
// 2. Define Roles and Inheritance
engine.defineRole({
name: 'Officer',
permissions: ['loan.read']
});
engine.defineRole({
name: 'Manager',
inherits: ['Officer'], // Inherits loan.read
permissions: ['loan.update', 'loan.approve']
});
engine.defineRole({
name: 'Admin',
inherits: ['Manager'], // Inherits Officer + Manager permissions
permissions: ['loan.*', 'report.download'] // Wildcards supported
});
// 3. Define Dynamic context rule
engine.defineRule({
action: 'loan.approve',
check: (user, context) => {
// User can approve only if they belong to the loan's branch
return user.branchId === context.branchId;
}
});
// 4. Perform Checks
const checkResult = await engine.check({
user: { id: 'usr-1', roles: ['Officer'], branchId: 'north-branch' },
action: 'loan.approve',
context: { branchId: 'north-branch' }
});
console.log(checkResult.allowed); // false (Officer lacks static permission to approve loans)
console.log(checkResult.explanation);
/*
Output:
{
decision: 'DENY',
reason: 'User is missing required permission: "loan.approve".',
missingPermission: 'loan.approve',
requiredRoles: ['Manager', 'Admin'],
currentRoles: ['Officer']
}
*/Advanced Capabilities
Multi-Tenant SaaS Isolation
Scope roles, permissions, and caches dynamically per tenant.
const engine = new PermissionEngine({
tenantResolver: (context) => context.tenantId
});
// Define same role name with different structures for different tenants
engine.defineRole({ name: 'Admin', permissions: ['loan.create'] }, 'TenantA');
engine.defineRole({ name: 'Admin', permissions: ['loan.read'] }, 'TenantB');Redis Caching with Failure Resiliency
If Redis goes down, node-rbac-kit continues to resolve authorization requests dynamically without throwing application-breaking exceptions.
import Redis from 'ioredis';
import { PermissionEngine, RedisCacheAdapter } from 'node-rbac-kit';
const redisClient = new Redis('redis://localhost:6379');
const cache = new RedisCacheAdapter(redisClient, {
defaultTtlSeconds: 600,
prefix: 'my-app-rbac'
});
const engine = new PermissionEngine({ cache });Visual Graph Generation
Exposes structural JSON trees representing your hierarchy—perfect for building visual admin panels.
const graph = engine.getPermissionGraph();
console.log(JSON.stringify(graph, null, 2));Diagnostics Validator
Scans your system for logical configuration errors.
const result = engine.validate(['loan.read', 'loan.write', 'report.download']);
console.log(result.isValid); // true or false
console.log(result.issues);
// Detects: Circular hierarchies, duplicate permissions, unused permissions, missing parents.Integrations
Express Middleware
Attach permission checks directly to your routes:
import express from 'express';
import { requirePermission } from 'node-rbac-kit';
const app = express();
app.get('/loans/:id',
requirePermission(engine, 'loan.read', {
getUser: (req) => req.session.user, // Customize user extraction
getContext: (req) => ({ tenantId: req.headers['x-tenant-id'] }) // Custom context
}),
(req, res) => {
res.send('Loan Details');
}
);NestJS Decorators & Guard
Secure controller endpoints using declarative metadata:
import { Controller, Get, UseGuards } from '@nestjs/common';
import { RBACGuard, Permission, HasRole } from 'node-rbac-kit';
@Controller('loans')
@UseGuards(RBACGuard)
export class LoanController {
@Get()
@Permission('loan.read')
findAll() {
return 'Loans list';
}
@Get('admin')
@HasRole('Admin')
adminPanel() {
return 'Admin dashboard';
}
}Register the engine as a NestJS provider:
import { Module } from '@nestjs/common';
import { PermissionEngine, RBACGuard } from 'node-rbac-kit';
@Module({
providers: [
{
provide: PermissionEngine,
useValue: new PermissionEngine()
},
{
provide: 'NESTJS_RBAC_OPTIONS',
useValue: {
getUser: (req) => req.user,
getContext: (req) => ({ tenantId: req.headers['x-tenant-id'] })
}
},
RBACGuard
],
exports: [PermissionEngine]
})
export class SecurityModule {}License
Custom Non-Commercial (See LICENSE file for details)