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.
Related Documents
- Configuration Documentation - For Redis configuration settings
- Environment Documentation - For Redis environment variables
- Authentication Documentation - For understand authentication system
- Activity Log Documentation - For tracking authorization-related user activities
- Term Policy Document - For managing user acceptance of terms and policies
Table of Contents
- Overview
- Related Documents
- User Protected
- Role Protected
- Policy Ability Protected
- Term Policy Acceptance Protected
- Creating Custom Roles
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:
- Authentication Check: Verifies that
request.userexists (populated by JWT strategy) - User Lookup: Retrieves user from database with role information
- User Existence: Ensures user record exists
- Status Validation: Confirms user status is
active - Password Expiry: Checks if password has expired
- Email Verification: Validates email verification if required
Flow Diagram:
Important Notes
@UserProtected()requires@AuthJwtAccessProtected()to be applied first (above in code)@AuthJwtAccessProtected()populatesrequest.userfrom JWT token. See Authentication Documentation for details- This decorator populates
request.__userwhich 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 accessEnumRoleType.admin- Administrator roleEnumRoleType.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:
- User Validation: Verifies that
request.__userandrequest.userexist - Super Admin Bypass: If user role is
superAdmin, grants immediate access with empty abilities array - Required Roles Check: Validates that required roles are defined
- Role Match: Confirms user’s role type matches one of the required roles
- Abilities Population: Attaches role abilities to
request.__abilitiesfor 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.__abilitieswhich is required by policy guards - Incorrect ordering will result in runtime errors
- Users with
superAdminrole type have unrestricted access to all@RoleProtectedroutes, 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 subjectEnumPolicyAction.read- Read/view permissionEnumPolicyAction.create- Create new resourcesEnumPolicyAction.update- Modify existing resourcesEnumPolicyAction.delete- Remove resources
Available Policy Subjects:
EnumPolicySubject.all- All resourcesEnumPolicySubject.apiKey- API key managementEnumPolicySubject.role- Role managementEnumPolicySubject.user- User managementEnumPolicySubject.session- Session managementEnumPolicySubject.activityLog- Activity logsEnumPolicySubject.passwordHistory- Password historyEnumPolicySubject.termPolicy- Terms and policiesEnumPolicySubject.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:
- User Validation: Verifies that
request.__userandrequest.userexist - Super Admin Bypass: If user role is
superAdmin, grants immediate access - Required Abilities Check: Validates that required abilities are defined
- Ability Creation: Creates CASL ability rules from user’s role abilities (
request.__abilities) - Permission Validation: Checks if user abilities match all required abilities
- 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 abilitieshandlerAbilities(): Validates if user has all required abilities using CASL’scan()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
superAdminrole type have unrestricted access to all@PolicyAbilityProtectedroutes, 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]onUSERsubject, 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 totermsOfServiceandprivacy
Available Term Policy Types:
EnumTermPolicyType.termsOfService- Terms of Service acceptanceEnumTermPolicyType.privacy- Privacy Policy acceptanceEnumTermPolicyType.cookies- Cookies Policy acceptanceEnumTermPolicyType.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:
- User Validation: Verifies that
request.__userandrequest.userexist - Default Policy Check: If no required policies specified, sets defaults to
termsOfServiceandprivacy - Term Policy Lookup: Retrieves user’s term policy acceptance status from
__user.termPolicy - Acceptance Validation: Checks if all required term policies are accepted
- 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
termsOfServiceandprivacyacceptance - 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:
- Authenticate as an admin user
- Call the role creation endpoint
- Provide role details including name, type, description, and abilities
- 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, futureFlagEnumPolicyAction: manage, read, create, update, delete
Assigning Roles to Users
Once a custom role is created, it can be assigned to users through:
- User creation: Specify the
roleIdwhen creating new users - 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
RoleGuardautomatically loads the user’s role and abilities during authentication - The
PolicyAbilityGuardvalidates 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