RBAC — Roles & Permissions
Role-based access control with multiple guards (web, api, mobile).
Nest Auth ships a full role-and-permission system. You can run multiple parallel role hierarchies — for example, "web roles" for browser users and "api roles" for service accounts — and check them per route.
Concepts
| Thing | What it is |
|---|---|
| Role | Named bucket — admin, editor, member. Lives in nest_auth_roles. |
| Permission | Fine-grained capability — orders.read, orders.write. Lives in nest_auth_permissions. |
| Role-permission | Many-to-many between the two. |
| Guard | A namespace for roles. 'web', 'api', 'mobile' — you decide. |
| User-tenant access | A user's role(s) within a tenant, on a specific guard. |
Configuring guards
Tell the module which guard namespaces exist:
A role row carries its guard, so an admin web role and an admin api role are independent records that don't conflict.
When you need multiple guards
The minimum useful set is one. Reach for multiple guards when the same backend serves several frontends that should authenticate independently — typically:
| Guard | Frontend | Roles you'd find here |
|---|---|---|
ADMIN | Internal admin console (separate origin) | super_admin, support, ops |
PORTAL | Tenant-facing SaaS app | owner, admin, member, billing |
FRONTEND | Mobile app (or public marketing site) | customer, guest |
A user can have roles on more than one guard — Alice could be admin on PORTAL and support on ADMIN. The library doesn't care; your loginHooks.onLogin decides which guard the user is allowed to log into based on the request's origin (or a header). See the multi-platform login recipe for the full pattern.
Creating roles per guard
A worked seeder migration with idempotent upserts: seeding-roles-and-permissions recipe.
Decorators
@Auth(true) makes auth optional — if the user is logged in, the guard populates the request context; if not, the route still runs.
@SkipMfa() lets a route bypass MFA enforcement (useful for the /auth/mfa/verify endpoint itself).
Checking from the client
The client and React layer ship matching utilities:
Or use guard components:
Where roles & permissions are evaluated
The default flow:
- User logs in. Server reads their
nest_auth_user_accessesrow for the active tenant. - Server resolves their roles, then expands roles → permissions via
nest_auth_role_permissions. - The full
roles[]andpermissions[]arrays are baked into the session payload (and thus intouseUser()). - Guards on protected routes check against those arrays — no per-request DB hit.
External role systems (Okta / Auth0 / custom IDP)
Don't want to store roles in your database? Replace the resolution step with a hook:
Both hooks run on every login and refresh. See the external role resolver recipe for a full example.
Assigning roles to users
Roles aren't useful until you attach them to a user × tenant pair. That mapping lives on NestAuthUserAccess (or NestAuthPlatformAccess for staff). The most common spot to assign a default role is the registrationHooks.onSignup hook — it runs after the user is created but before the first session is built, so the role lands in the very first JWT.
For programmatic role/permission management from your own services (admin endpoints, invitation flows, role-change UIs), use RoleService and PermissionService. They cover create / update / delete / assign / list, emit the matching events, and respect isSystem protection.
System vs custom roles
Roles can be marked isSystem: true. Those are protected — the admin console won't let users delete or rename them, and the library treats them as canonical. Use this for the handful of roles your code references by name (admin, member, owner); leave isSystem: false for end-user-defined roles ("Marketing Lead", "QA Manager") that admins can edit freely.
Related
- User Access & Platform Access — where role assignments live.
- Multi-tenancy — roles are per-tenant by default.
- Hooks reference —
authorization.resolveRoles/resolvePermissions. - External role resolver recipe.
- Multi-platform login recipe — guards in production.
- Seeding roles & permissions recipe.