nestjstutorial
Tutorial: wiring up the NestJS RbacGuard
This drives RbacGuard directly against a Reflector and a fake ExecutionContext — the same technique the adapter's own test suite uses — so you can see all four outcomes without a full @nestjs/cli build step.
Set up roles and the guard
import 'reflect-metadata';
import { Reflector } from '@nestjs/core';
import { RBAC } from 'rbac-fs';
import { RbacGuard, RequirePermission } from 'rbac-fs/nestjs';
const rbac = new RBAC({ tenantId: 'acme-corp' });
await rbac.createRole('manager', { permissions: [{ resource: 'invoice', actions: ['approve'] }] }, { force: true });
await rbac.createRole('viewer', { permissions: [{ resource: 'invoice', actions: ['view'] }] }, { force: true });
const guard = new RbacGuard(new Reflector(), rbac);A controller with one guarded route, one not
class InvoiceController {
@RequirePermission('invoice', 'approve')
approve(): { approved: true } {
return { approved: true };
}
comment(): { commented: true } { // deliberately no @RequirePermission()
return { commented: true };
}
}Run all four scenarios
function contextFor(handler, request) {
return {
getHandler: () => handler,
getClass: () => InvoiceController,
switchToHttp: () => ({ getRequest: () => request, getResponse: () => ({}), getNext: () => undefined }),
};
}
// 1. manager, guarded route -> allowed
await guard.canActivate(contextFor(InvoiceController.prototype.approve, { user: { id: 'u1', role: 'manager' } })); // true
// 2. no decorator on the route -> allowed unchecked
await guard.canActivate(contextFor(InvoiceController.prototype.comment, { user: { id: 'u1', role: 'manager' } })); // true
// 3. guarded route, no request.user -> throws
await guard.canActivate(contextFor(InvoiceController.prototype.approve, {})); // ForbiddenException
// 4. viewer without the permission -> throws
await guard.canActivate(contextFor(InvoiceController.prototype.approve, { user: { id: 'u2', role: 'viewer' } })); // ForbiddenExceptionRun this yourself with node --import tsx — no Angular-style AOT/JIT pipeline needed for this level of verification, since it bypasses Nest's own @Post()/@Controller() decorators (which do need the real @nestjs/cli build to emit design:paramtypes metadata).
Verified against examples/10-nestjs-guard.ts, which runs this exact sequence.