Skip to Content
Authorization Documentation

Authorization Documentation

This documentation explains the features and usage of:

  • UserProtected: Located at src/modules/user/decorators
  • RoleProtected: Located at src/modules/role/decorators
  • PolicyAbilityProtected: Located at src/modules/policy/decorators
  • TermPolicyAcceptanceProtected: Located at src/modules/term-policy/decorators

Overview

This authorization system provides a comprehensive, layered security approach for Complete NestJs Boilerplate. It implements multiple protection levels including user authentication, role-based access control, policy-based permissions, and terms acceptance verification.

The system is built using NestJS guards and decorators, making it easy to apply different authorization levels to your route handlers with simple, declarative syntax.

Table of Contents

User Protected

UserProtected provides basic user authentication and verification. It ensures that only authenticated users can access protected routes and optionally validates whether the user’s email has been verified.

Decorators

UserProtected Decorator

Method decorator that applies UserGuard to route handlers.

Parameters:

  • isVerified (boolean, optional): Whether to require email verification. Default: true

Usage:

@UserProtected() @AuthJwtAccessProtected() @Get('profile') getProfile(@UserCurrent() user: IUser) { return user; } // Allow unverified users @UserProtected(false) @AuthJwtAccessProtected() @Get('dashboard') getDashboard(@UserCurrent() user: IUser) { return { user }; }

UserCurrent Parameter Decorator

Extracts the authenticated user object from the request context.

Returns: IUser | undefined

Usage:

@UserProtected() @AuthJwtAccessProtected() @Get('me') getCurrentUser(@UserCurrent() user: IUser) { return { id: user.id, email: user.email, role: user.role }; }

Guards

UserGuard

The guard implementation that performs the actual validation.

The UserProtected decorator follows this validation sequence:

  1. Authentication Check: Verifies that request.user exists (populated by JWT strategy)
  2. User Lookup: Retrieves user from database with role information
  3. User Existence: Ensures user record exists
  4. Status Validation: Confirms user status is active
  5. Password Expiry: Checks if password has expired
  6. Email Verification: Validates email verification if required

Flow Diagram:

Important Notes

  • @UserProtected() requires @AuthJwtAccessProtected() to be applied first (above in code)
  • @AuthJwtAccessProtected() populates request.user from JWT token. See Authentication Documentation for details
  • This decorator populates request.__user which is required by downstream guards

Role Protected

RoleProtected implements role-based access control (RBAC) to restrict route access based on user roles. It ensures that only users with specific role types can access protected endpoints.

Decorators

RoleProtected Decorator

Method decorator that applies RoleGuard to route handlers.

Parameters:

  • ...requiredRoles (EnumRoleType[]): One or more role types required to access the route

Available Role Types:

  • EnumRoleType.superAdmin - Super administrator with unrestricted access
  • EnumRoleType.admin - Administrator role
  • EnumRoleType.user - Standard user role

Usage:

// Single role requirement @RoleProtected(EnumRoleType.admin) @UserProtected() @AuthJwtAccessProtected() @Get('admin/dashboard') getAdminDashboard(@UserCurrent() user: IUser) { return this.dashboardService.getAdminData(); } // Multiple role requirements (user must have one of the specified roles) @RoleProtected(EnumRoleType.admin, EnumRoleType.superAdmin) @UserProtected() @AuthJwtAccessProtected() @Delete('users/:id') deleteUser(@Param('id') id: string) { return this.userService.delete(id); }

Getting Current Role

To access the current user’s role, use the @UserCurrent() decorator and access the role property:

@RoleProtected(EnumRoleType.admin) @UserProtected() @AuthJwtAccessProtected() @Get('role-info') getRoleInfo(@UserCurrent() user: IUser) { return { roleType: user.role.type, roleName: user.role.name, abilities: user.role.abilities }; }

Guards

RoleGuard

The guard implementation that validates user roles and populates role abilities.

The RoleProtected decorator follows this validation sequence:

  1. User Validation: Verifies that request.__user and request.user exist
  2. Super Admin Bypass: If user role is superAdmin, grants immediate access with empty abilities array
  3. Required Roles Check: Validates that required roles are defined
  4. Role Match: Confirms user’s role type matches one of the required roles
  5. Abilities Population: Attaches role abilities to request.__abilities for downstream use

Flow Diagram:

Important Notes

  • @RoleProtected() requires @AuthJwtAccessProtected() and @UserProtected() to be applied
  • @AuthJwtAccessProtected() must be placed at the bottom, followed by @RoleProtected(), then @UserProtected(). See Authentication Documentation for @AuthJwtAccessProtected() details
  • This decorator populates request.__abilities which is required by policy guards
  • Incorrect ordering will result in runtime errors
  • Users with superAdmin role type have unrestricted access to all @RoleProtected routes, regardless of the specified required roles. The guard returns an empty abilities array for super admins, as they bypass ability checks.

Policy Ability Protected

Purpose

PolicyAbilityProtected implements fine-grained, permission-based access control using CASL (an isomorphic authorization library). It allows you to define specific actions (read, create, update, delete, manage) that users can perform on specific subjects (resources like users, roles, settings, etc.).

PolicyAbilityProtected Decorator

Method decorator that applies PolicyAbilityGuard to route handlers.

Parameters:

  • ...requiredAbilities (RoleAbilityRequestDto[]): One or more policy ability objects defining required permissions

Available Policy Actions:

  • EnumPolicyAction.manage - Full control over a subject
  • EnumPolicyAction.read - Read/view permission
  • EnumPolicyAction.create - Create new resources
  • EnumPolicyAction.update - Modify existing resources
  • EnumPolicyAction.delete - Remove resources

Available Policy Subjects:

  • EnumPolicySubject.all - All resources
  • EnumPolicySubject.apiKey - API key management
  • EnumPolicySubject.role - Role management
  • EnumPolicySubject.user - User management
  • EnumPolicySubject.session - Session management
  • EnumPolicySubject.activityLog - Activity logs
  • EnumPolicySubject.passwordHistory - Password history
  • EnumPolicySubject.termPolicy - Terms and policies
  • EnumPolicySubject.futureFlag - Feature flags

Usage:

// Single ability requirement @PolicyAbilityProtected({ subject: EnumPolicySubject.user, action: [EnumPolicyAction.read] }) @RoleProtected(EnumRoleType.admin) @UserProtected() @AuthJwtAccessProtected() @Get('users') getUsers() { return this.userService.findAll(); } // Multiple actions on single subject @PolicyAbilityProtected({ subject: EnumPolicySubject.user, action: [EnumPolicyAction.update, EnumPolicyAction.delete] }) @RoleProtected(EnumRoleType.admin) @UserProtected() @AuthJwtAccessProtected() @Put('users/:id') updateUser(@Param('id') id: string, @Body() dto: UpdateUserDto) { return this.userService.update(id, dto); } // Multiple ability requirements (different subjects) @PolicyAbilityProtected( { subject: EnumPolicySubject.role, action: [EnumPolicyAction.read] }, { subject: EnumPolicySubject.user, action: [EnumPolicyAction.manage] } ) @RoleProtected(EnumRoleType.admin) @UserProtected() @AuthJwtAccessProtected() @Post('users/:id/assign-role') assignRole(@Param('id') id: string, @Body() dto: AssignRoleDto) { return this.userService.assignRole(id, dto.roleId); }

Guards

PolicyAbilityGuard

The guard implementation that validates user abilities using CASL library.

The PolicyAbilityProtected decorator follows this validation sequence:

  1. User Validation: Verifies that request.__user and request.user exist
  2. Super Admin Bypass: If user role is superAdmin, grants immediate access
  3. Required Abilities Check: Validates that required abilities are defined
  4. Ability Creation: Creates CASL ability rules from user’s role abilities (request.__abilities)
  5. Permission Validation: Checks if user abilities match all required abilities
  6. Access Decision: Grants or denies access based on permission match

Flow Diagram:

CASL Integration

The system uses CASL  (Code Access Security Library) to handle complex permission logic:

PolicyAbilityFactory:

  • createForUser(): Builds CASL ability rules from user’s assigned abilities
  • handlerAbilities(): Validates if user has all required abilities using CASL’s can() method

How it works:

The factory creates a CASL ability instance that can check if a user can perform specific actions on specific subjects. Every required ability must be satisfied for access to be granted.

Important Notes

  • @PolicyAbilityProtected() requires @AuthJwtAccessProtected(), @RoleProtected(), and @UserProtected() to be applied
  • Decorators must be stacked in this order from bottom to top: @PolicyAbilityProtected()@RoleProtected()@UserProtected()@AuthJwtAccessProtected(). See Authentication Documentation for @AuthJwtAccessProtected() details
  • Incorrect ordering will result in runtime errors
  • Users with superAdmin role type have unrestricted access to all @PolicyAbilityProtected routes, bypassing all ability checks.
  • All actions in a required ability must be present in the user’s abilities. For example, if you require [UPDATE, DELETE] on USER subject, the user must have both actions, not just one.

Term Policy Acceptance Protected

TermPolicyAcceptanceProtected validates that users have accepted required legal terms and policies (such as Terms of Service, Privacy Policy, etc.) before allowing access to protected routes. This ensures legal compliance and user consent management.

For more detailed information about term policies, see Term Policy Document.

Decorators

TermPolicyAcceptanceProtected Decorator

Method decorator that applies TermPolicyGuard to route handlers.

Parameters:

  • ...requiredTermPolicies (EnumTermPolicyType[], optional): One or more term policy types that must be accepted. If not provided, defaults to termsOfService and privacy

Available Term Policy Types:

  • EnumTermPolicyType.termsOfService - Terms of Service acceptance
  • EnumTermPolicyType.privacy - Privacy Policy acceptance
  • EnumTermPolicyType.cookies - Cookies Policy acceptance
  • EnumTermPolicyType.marketing - Marketing consent acceptance

Usage:

// Default: requires termsOfService and privacy acceptance @TermPolicyAcceptanceProtected() @UserProtected() @AuthJwtAccessProtected() @Get('premium-features') getPremiumFeatures() { return this.featureService.getPremiumFeatures(); } // Single term policy requirement @TermPolicyAcceptanceProtected(EnumTermPolicyType.marketing) @UserProtected() @AuthJwtAccessProtected() @Post('subscribe-newsletter') subscribeNewsletter(@Body() dto: SubscribeDto) { return this.newsletterService.subscribe(dto); } // Multiple term policy requirements @TermPolicyAcceptanceProtected( EnumTermPolicyType.termsOfService, EnumTermPolicyType.privacy, EnumTermPolicyType.cookies ) @UserProtected() @AuthJwtAccessProtected() @Post('data-processing') processUserData(@Body() dto: ProcessDataDto) { return this.dataService.process(dto); }

Guards

TermPolicyGuard

The guard implementation that validates user term policy acceptance.

The TermPolicyAcceptanceProtected decorator follows this validation sequence:

  1. User Validation: Verifies that request.__user and request.user exist
  2. Default Policy Check: If no required policies specified, sets defaults to termsOfService and privacy
  3. Term Policy Lookup: Retrieves user’s term policy acceptance status from __user.termPolicy
  4. Acceptance Validation: Checks if all required term policies are accepted
  5. Access Decision: Grants access only if all required policies are accepted

Flow Diagram:

Important Notes

  • @TermPolicyAcceptanceProtected() requires @UserProtected() and @AuthJwtAccessProtected() to be applied
  • Decorator order from top to bottom: @TermPolicyAcceptanceProtected()@UserProtected()@AuthJwtAccessProtected()
  • For more details about @AuthJwtAccessProtected(), see Authentication Documentation
  • Without the required decorators, the endpoint will throw a 403 Forbidden error
  • If no term policies are specified, it defaults to requiring termsOfService and privacy acceptance
  • All specified term policies must be accepted by the user for access to be granted
  • Incorrect decorator ordering will result in runtime errors

Creating Custom Roles

The boilerplate supports creating custom roles through the role management API. Each role can have a unique combination of permissions (abilities) that define what actions users with that role can perform on different resources.

This feature allows you to create specialized roles beyond the default superAdmin, admin, and user types - for example, you could create roles like “ContentModerator”, “Accountant”, “CustomerSupport”, etc., each with their own specific set of permissions.

How to Create a New Role

Custom roles are created through the admin role management endpoints. The API documentation is available in your Swagger docs at /docs.

Basic steps:

  1. Authenticate as an admin user
  2. Call the role creation endpoint
  3. Provide role details including name, type, description, and abilities
  4. The new role is immediately available for assignment to users

Example role creation request:

{ "name": "contentmoderator", "description": "Role for moderating user-generated content", "type": "admin", "abilities": [ { "subject": "user", "action": ["read", "update"] }, { "subject": "activityLog", "action": ["read"] } ] }

Role Configuration

Role Properties:

  • name: Unique identifier for the role (alphanumeric, lowercase, 3-30 characters)
  • description: Optional description explaining the role’s purpose (max 500 characters)
  • type: Role type from EnumRoleType (superAdmin, admin, or user)
  • abilities: Array of permission objects defining what the role can do

Ability Structure:

Each ability consists of:

  • subject: The resource type (e.g., user, role, apiKey, session, termPolicy, activityLog)
  • action: Array of allowed actions (manage, read, create, update, delete)

Available subjects and actions are defined in:

  • EnumPolicySubject: all, apiKey, role, user, session, activityLog, passwordHistory, termPolicy, futureFlag
  • EnumPolicyAction: manage, read, create, update, delete

Assigning Roles to Users

Once a custom role is created, it can be assigned to users through:

  1. User creation: Specify the roleId when creating new users
  2. User update: Update existing users to assign them the new role

How it works automatically:

  • When a user is assigned a role, they immediately inherit all abilities defined for that role
  • The RoleGuard automatically loads the user’s role and abilities during authentication
  • The PolicyAbilityGuard validates permissions based on the role’s abilities
  • No application restart or additional configuration is needed

Permission enforcement flow:

Important Notes

  • Role names must be unique - You cannot create two roles with the same name
  • Roles cannot be deleted if in use - You must first reassign users to different roles before deleting
Last updated on