← Back to Chapters

Routing Guards & Role Conditional Guards

?️ Routing Guards & Role Conditional Guards

Angular Routing Role-Based Access

? Quick Overview

In Angular, routing guards control whether a user can navigate to a route. When combined with role-based access control and conditional routing, they enable powerful and flexible navigation strategies.

In this topic, you will learn how to use:

  • Advanced role-based guards (Admin, Manager, etc.).
  • Chaining multiple guards for complex logic.
  • Guards with lazy-loaded modules for better performance.
  • Redirecting unauthorized users to a /forbidden route.

? Key Concepts

  • Routing Guard: A service that decides if a route can be activated, loaded, or left.
  • Role-Based Guard: Guard that checks the current user's role (e.g., admin, manager).
  • Chaining Guards: Using multiple guards together on a single route.
  • Lazy Loading with Guards: Protecting a feature module that is loaded only when needed.
  • Role-Based Redirects: Redirecting unauthorized users to a safe page like /forbidden.

? Syntax & Theory

A typical role-based guard relies on an authentication / authorization service that stores the current user's role. The guard uses this information to decide if a route should be accessible or not.

Commonly used guard interfaces in Angular:

  • CanActivate – Check before navigating to a route.
  • CanLoad – Check before loading a lazy-loaded module.
  • CanActivateChild – Check access to child routes.

? Advanced Role-Based Guards – Auth Service

First, create an AuthService that manages the current user's role and exposes helper methods like isAdmin() and isManager().

? View Code Example – auth.service.ts
// Auth service managing user roles for guards
import { Injectable } from '@angular/core';

@Injectable({ providedIn: 'root' })
export class AuthService {
private userRole: string = 'user';

getRole(): string {
return this.userRole;
}

isAdmin(): boolean {
return this.userRole === 'admin';
}

isManager(): boolean {
return this.userRole === 'manager';
}

setRole(role: string) {
this.userRole = role;
}
}

? Multiple Role Guard

Now create a guard that allows access if the user is either an Admin or a Manager. Otherwise, the user is redirected to the /forbidden route.

? View Code Example – multiple-role.guard.ts
// Guard that allows Admin or Manager users
import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';
import { AuthService } from './auth.service';

@Injectable({ providedIn: 'root' })
export class MultipleRoleGuard implements CanActivate {
constructor(private auth: AuthService, private router: Router) {}

canActivate(): boolean {
if (this.auth.isAdmin() || this.auth.isManager()) {
return true;
}
// Redirect unauthorized users to a forbidden page
this.router.navigate(['/forbidden']);
return false;
}
}

? Chaining Guards for Complex Logic

Multiple guards can be applied to a single route. For example, you may first check if the user is authenticated and then verify their role.

? View Code Example – app.routes.ts (Chaining)
// Route configuration with chained guards
import { Routes } from '@angular/router';
import { DashboardComponent } from './dashboard/dashboard.component';
import { MultipleRoleGuard } from './multiple-role.guard';
import { AuthGuard } from './auth.guard';

export const routes: Routes = [
{
path: 'dashboard',
component: DashboardComponent,
canActivate: [AuthGuard, MultipleRoleGuard]
},
{
path: 'forbidden',
loadComponent: () =>
import('./forbidden/forbidden.component').then(m => m.ForbiddenComponent)
}
];

? Role-Based Guards with Lazy Loading

For large applications, it's common to lazy-load feature modules like AdminModule. You can protect these lazy-loaded modules using role-based guards.

? View Code Example – Lazy-Loaded Admin Module
// app.routes.ts with lazy-loaded admin module and role guard
import { Routes } from '@angular/router';
import { RoleGuard } from './role.guard';
import { ForbiddenComponent } from './forbidden/forbidden.component';

export const routes: Routes = [
{
path: 'admin',
loadChildren: () =>
import('./admin/admin.module').then(m => m.AdminModule),
canActivate: [RoleGuard]
},
{
path: 'forbidden',
component: ForbiddenComponent
}
];

? How It Works (Step-by-Step)

  1. The user logs in and their role is stored in AuthService (e.g., admin or user).
  2. When the user tries to navigate to a protected route (e.g., /dashboard or /admin), Angular checks the configured guards.
  3. AuthGuard ensures the user is authenticated.
  4. MultipleRoleGuard / RoleGuard ensures the user has the required role.
  5. If all guards return true, navigation continues; otherwise, the user is redirected to /forbidden.
  6. For lazy-loaded modules, the guard runs before the module is loaded, saving bandwidth and improving performance.

✅ Tips & Best Practices

  • Use canLoad to avoid loading a module if the user is not allowed to access it.
  • Keep role logic centralized inside services (like AuthService) instead of hardcoding roles in multiple guards.
  • Combine guards logically: first check authentication, then roles, then maybe feature flags or subscription status.
  • Reuse guards across routes to keep your routing configuration DRY (Don't Repeat Yourself).
  • Log unauthorized access attempts for debugging and audit purposes.

? Try It Yourself

  • Create a VIPGuard that only allows users with role vip to access a /vip-area route.
  • Implement canLoad on a lazy-loaded ReportsModule so only managers can load reports.
  • Chain AuthGuard, MultipleRoleGuard, and a custom SubscriptionGuard for a premium dashboard route.
  • Add a /forbidden component that displays a friendly message and a button to go back to a safe page.
  • Extend AuthService to support multiple roles per user (e.g., ['admin', 'editor']) and update your guards accordingly.