1. Why Do We Need Route Guards in Angular?
What is the need?
We need route guards to control whether a user should be allowed to navigate to a particular Angular route.
Without guards, a user could manually enter URLs such as:
/admin
/dashboard
/reports
and Angular would navigate to those routes if they exist.
With a guard:
User requests /admin
↓
Route Guard
↓
Check condition
↓
Allowed? ── Yes ──→ Admin Page
│
No
↓
Login / Access Denied
Why Do We Need Them?
Common requirements include:
Authentication
Check whether the user is logged in.
/dashboard
↓
Logged in?
↓
Yes → Dashboard
No → Login
Authorization
Check whether the logged-in user has permission.
/admin
↓
Logged in? → Yes
↓
Role = Admin?
↓
Yes → Admin
No → Access Denied
Unsaved Changes
Prevent accidental navigation away from an edited form.
Edit Product
↓
User clicks Home
↓
Unsaved changes?
↓
"Do you want to leave?"
Conditional Route Access
Routes can also depend on feature flags, subscription state, application state, etc.
2. What is an Authentication Guard?
What is it?
An authentication guard checks whether the user is authenticated (logged in) before allowing access to a route.
The question it answers is:
Who are you, and are you logged in?
Example:
User → /dashboard
↓
Auth Guard
↓
Logged in?
/ \
Yes No
↓ ↓
Dashboard /login
Full Simple Authentication Guard Program
auth.service.ts
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class AuthService {
private loggedIn = false;
login(): void {
this.loggedIn = true;
}
logout(): void {
this.loggedIn = false;
}
isLoggedIn(): boolean {
return this.loggedIn;
}
}
auth.guard.ts
import { inject } from '@angular/core';
import { CanActivateFn, Router } from '@angular/router';
import { AuthService } from './auth.service';
export const authGuard: CanActivateFn = () => {
const authService = inject(AuthService);
const router = inject(Router);
if (authService.isLoggedIn()) {
return true;
}
return router.createUrlTree(['/login']);
};
dashboard.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-dashboard',
standalone: true,
template: `
<h2>Dashboard</h2>
<p>Welcome to Dashboard</p>
`
})
export class Dashboard {
}
login.ts
import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { AuthService } from './auth.service';
@Component({
selector: 'app-login',
standalone: true,
template: `
<h2>Login</h2>
<button (click)="login()">
Login
</button>
`
})
export class Login {
constructor(
private authService: AuthService,
private router: Router
) {
}
login(): void {
this.authService.login();
this.router.navigate(['/dashboard']);
}
}
app.routes.ts
import { Routes } from '@angular/router';
import { Login } from './login';
import { Dashboard } from './dashboard';
import { authGuard } from './auth.guard';
export const routes: Routes = [
{
path: 'login',
component: Login
},
{
path: 'dashboard',
component: Dashboard,
canActivate: [authGuard]
}
];
How Authentication Guard Works
The important configuration:
{
path: 'dashboard',
component: Dashboard,
canActivate: [authGuard]
}
Before Angular activates Dashboard, it executes:
authGuard
The guard checks:
authService.isLoggedIn()
If logged in:
return true;
Navigation continues.
If not logged in:
return router.createUrlTree(['/login']);
Angular redirects to Login.
3. What is an Authorization Guard?
What is it?
An authorization guard checks whether an authenticated user has the required role or permission to access a route.
The question it answers is:
You are logged in, but are you allowed to access this page?
For example:
Logged-in User
↓
/admin
↓
Authorization Guard
↓
Role = Admin?
/ \
Yes No
↓ ↓
Admin Access
Page Denied
Full Simple Authorization Guard Program
Suppose our application has two roles:
Admin
User
Only Admin should access:
/admin
auth.service.ts
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class AuthService {
private loggedIn = true;
private role = 'Admin';
isLoggedIn(): boolean {
return this.loggedIn;
}
getRole(): string {
return this.role;
}
}
admin.guard.ts
import { inject } from '@angular/core';
import { CanActivateFn, Router } from '@angular/router';
import { AuthService } from './auth.service';
export const adminGuard: CanActivateFn = () => {
const authService = inject(AuthService);
const router = inject(Router);
if (!authService.isLoggedIn()) {
return router.createUrlTree(['/login']);
}
if (authService.getRole() === 'Admin') {
return true;
}
return router.createUrlTree(['/access-denied']);
};
admin.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-admin',
standalone: true,
template: `
<h2>Admin Page</h2>
<p>Only administrators can access this page.</p>
`
})
export class Admin {
}
access-denied.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-access-denied',
standalone: true,
template: `
<h2>Access Denied</h2>
<p>
You don't have permission to access this page.
</p>
`
})
export class AccessDenied {
}
app.routes.ts
import { Routes } from '@angular/router';
import { Admin } from './admin';
import { AccessDenied } from './access-denied';
import { adminGuard } from './admin.guard';
export const routes: Routes = [
{
path: 'admin',
component: Admin,
canActivate: [adminGuard]
},
{
path: 'access-denied',
component: AccessDenied
}
];
How Authorization Guard Works
Suppose:
role = 'Admin';
User requests:
/admin
The flow is:
/admin
↓
adminGuard
↓
Logged in?
↓
Yes
↓
Role == Admin?
↓
Yes
↓
return true
↓
Admin Page
If the role is:
role = 'User';
then:
/admin
↓
adminGuard
↓
Logged in?
↓
Yes
↓
Role == Admin?
↓
No
↓
/access-denied
Authentication vs Authorization
This is the most important interview distinction.
| Authentication | Authorization |
|---|---|
| Checks identity/login | Checks permission/access |
| Who are you? | What are you allowed to do? |
| Is user logged in? | Does user have required role/permission? |
| Usually happens first | Usually happens after authentication |
| Example: valid login/token | Example: Admin role |
| Failure → Login | Failure → Access Denied |
Think:
Authentication
↓
"Who are you?"
↓
Syed is logged in
↓
Authorization
↓
"What can you access?"
↓
Admin? User? Required permission?
Authentication + Authorization Together
In a real application, both are often needed.
For example:
User requests /admin
↓
Authentication
↓
Is user logged in?
/ \
No Yes
↓ ↓
Login Authorization
↓
Is Admin?
/ \
Yes No
↓ ↓
Admin Access
Page Denied
You could also separate the checks into two guards.
{
path: 'admin',
component: Admin,
canActivate: [
authGuard,
adminGuard
]
}
Conceptually:
/admin
↓
authGuard
↓
Authenticated?
↓
adminGuard
↓
Authorized?
↓
Admin Component
Real-World JWT Example
In an Angular + ASP.NET Core application, the login flow might be:
Angular Login
↓
POST /api/auth/login
↓
ASP.NET Core API
↓
Validate username/password
↓
JWT returned
↓
Angular authentication state
↓
Route Guard
The token may contain claims such as:
{
"sub": "123",
"name": "Syed",
"role": "Admin"
}
Conceptually:
Authentication guard
Checks whether the application has a valid authenticated session/state.
Is user authenticated?
Authorization guard
Checks:
Does user have Admin role?
or:
Does user have required permission?
Important Security Point
Angular route guards are not a security boundary.
Even if Angular prevents:
/admin
the user could attempt to call the backend directly:
GET /api/admin/users
Therefore, ASP.NET Core must independently protect the API.
For example:
[Authorize]
[HttpGet]
public IActionResult GetProfile()
{
// ...
}
For authorization:
[Authorize(Roles = "Admin")]
[HttpGet]
public IActionResult GetUsers()
{
// ...
}
Architecture:
Angular
↓
Route Guard
↓
Controls UI navigation
↓
ASP.NET Core Web API
↓
[Authorize]
↓
Actual server-side security
Key Points
- Route guards control navigation in Angular.
- Authentication guard checks whether the user is logged in/authenticated.
- Authorization guard checks whether the authenticated user has the required role or permission.
- Authentication answers:
Who are you?
- Authorization answers:
What are you allowed to access?
- Common authentication failure:
Redirect → /login
- Common authorization failure:
Redirect → /access-denied
- Modern Angular commonly uses functional guards such as:
CanActivateFn
- Route guards improve client-side navigation and UX, but backend authorization must still be enforced.
Interview Questions and Answers
1. Why do we need route guards?
Route guards control access to Angular routes based on conditions such as authentication, roles, permissions, or unsaved changes.
2. What is an authentication guard?
An authentication guard checks whether the user is authenticated before allowing access to a protected route.
if (authService.isLoggedIn()) {
return true;
}
return router.createUrlTree(['/login']);
3. What is an authorization guard?
An authorization guard checks whether an authenticated user has the required role or permission.
if (authService.getRole() === 'Admin') {
return true;
}
return router.createUrlTree(['/access-denied']);
4. Authentication vs authorization?
Authentication verifies the user's identity/login state.
Authorization determines what that authenticated user is allowed to access.
5. Which normally happens first?
Authentication normally happens first:
Authentication
↓
Authorization
First establish the user's identity, then evaluate their permissions.
6. Are Angular guards enough to secure an application?
No. Angular guards only control client-side routing. Sensitive backend endpoints must also enforce authentication and authorization.
Interview-ready answer
Route guards are used to control access to Angular routes. An authentication guard checks whether the user is logged in and typically redirects unauthenticated users to the login page. An authorization guard checks whether the authenticated user has the required role or permission and may redirect unauthorized users to an Access Denied page. Authentication answers “Who are you?”, while authorization answers “What are you allowed to access?”. Backend APIs must still enforce their own security.