
- Angular Tutorial
- Angular - Home
- Angular - Overview
- Angular - Features
- Angular - Advantages & Disadvantages
- Angular Basics
- Angular - Environment setup
- Angular - First Application
- Angular - MVC Architecture
- Angular Components
- Angular - Components
- Angular - Component Lifecycle
- Angular - View Encapsulation
- Angular - Component Interaction
- Angular - Component Styles
- Angular - Nested Components
- Angular - Content projection
- Angular - Dynamic components
- Angular - Elements
- Angular Templates
- Angular - Templates
- Angular - Template statements
- Angular - Template Variables
- Angular - SVG as Templates
- Angular Binding
- Angular - Data Binding
- Angular - Interpolation
- Angular - Event Binding
- Angular - Property Binding
- Angular - Attribute Binding
- Angular - Class Binding
- Angular - Style Binding
- Angular - Two-way Binding
- Angular Directives
- Angular - Directives
- Angular - Attribute Directives
- Angular - Structural Directives
- Angular - Custom Directives
- Angular Pipes
- Angular - Pipes
- Angular - Built-in Pipes
- Angular - Custom Pipes
- Angular Forms
- Angular - Forms
- Angular - Template Driven Forms
- Angular - Reactive Forms
- Angular - Form Validation
- Angular - Dynamic Forms
- Angular Dependency Injection
- Angular - Dependency Injection
- Angular - Injectable Service
- Angular Routing
- Angular - Routing
- Angular - Dynamic Routes
- Angular - Wildcard Routes
- Angular - Nested Routes
- Angular - Navigation
- Angular - Routing in SPA
- Angular - Custom Route Matches
- Angular - Router Reference
- Angular HTTP Client programming
- Angular - Services
- Angular - HTTP Client
- Angular - Request
- Angular - Response
- Angular - GET
- Angular - POST
- Angular - PUT
- Angular - DELETE
- Angular - JSONP
- Angular - CRUD Operations Using HTTP
- Angular Modules
- Angular - Introduction to Modules
- Angular - Root Module
- Angular - Feature Module
- Angular - Sharing Module
- Angular - Routing Module
- Angular - NgModules
- Angular Animation
- Angular - Animations
- Angular Service Workers & PWA
- Angular - Service Workers & PWA
- Angular Testing
- Angular - Testing Overview
- Angular Design Patterns
- Angular - Design Patterns
- Angular - Lazy Loading
- Angular - Singleton Pattern
- Angular - Observer Pattern
- Angular Libraries
- Angular - Libraries
- Angular - Angular Material
- Angular - PrimeNG
- Angular - RxJS
- Angular Advanced
- Angular - Signals
- Angular - Authentication & Authorization
- Angular - Internationalization
- Angular - Standalone Component
- Angular - Accessibility
- Angular - Web Workers
- Angular - Server Side Rendering
- Angular - Ivy Compiler
- Angular - Building with Bazel
- Angular - Backward Compatibility
- Angular - Reactive Programming
- Angular Tools
- Angular - CLI
- Angular Material UI Elements
- Angular - Paginator
- Angular - Datepicker
- Angular - Select Drop-down
- Angular Miscellaneous
- Angular - Third Party Controls
- Angular - Configuration
- Angular - Displaying Data
- Angular - Decorators & Metadata
- Angular - Basic Example
- Angular - Error Handling
- Angular - Testing & Building a Project
- Angular - Lifecycle Hooks
- Angular - User Input
- Angular - What's New?
- Angular Useful Resources
- Angular - Quick Guide
- Angular - Useful Resources
- Angular - Discussion
Angular - Authentication and Authorization
Authentication is the process matching the visitor of a web application with the pre-defined set of user identity in the system. In other word, it is the process of recognizing the users identity. Authentication is very important process in the system with respect to security.
Authorization is the process of giving permission to the user to access certain resource in the system. Only the authenticated user can be authorized to access a resource.
Let us learn how to do Authentication and Authorization in Angular application in this tutorial.
Guards in Routing
In a web application, a resource is referred by url. Every user in the system will be allowed access a set of urls. For example, an administrator may be assigned all the url coming under administration section.
As we know already, URLs are handled by Routing. Angular routing enables the urls to be guarded and restricted based on programming logic. So, a url may be denied for a normal user and allowed for an administrator.
Angular provides a concept called Router Guards which can be used to prevent unauthorized access to certain part of the application through routing. Angular provides multiple guards and they are as follows:
CanActivate: Used to stop the access to a route.
CanActivateChild: Used to stop the access to a child route.
CanDeactivate: Used to stop ongoing process getting feedback from user. For example, delete process can be stop if the user replies in negative.
Resolve: Used to pre-fetch the data before navigating to the route.
CanLoad: Used to load assets.
Working Example
In this example, we are going to add login and logout functionality to an angular application and secure it using CanActivate guard. Follow the given steps:
Step 1: Create an angular application using the following command −
ng new new-app
Step 2: Now, navigate to project root folder.
cd new-app
Step 3: Next, we include the Bootstrap into our new-app application using styles option and change the default template to use Bootstrap components. Use the below command to install Bootstrap and JQuery in the project −
npm install --save bootstrap jquery
Now, open angular.json file and set bootstrap and jquery library path −
{ "projects": { "expense-manager": { "architect": { "build": { "builder":"@angular-devkit/build-angular:browser", "options": { "outputPath": "dist/expense-manager", "index": "src/index.html", "main": "src/main.ts", "polyfills": "src/polyfills.ts", "tsConfig": "tsconfig.app.json", "aot": false, "assets": [ "src/favicon.ico", "src/assets" ], "styles": [ "./node_modules/bootstrap/dist/css/bootstrap.css", "src/styles.css" ], "scripts": [ "./node_modules/jquery/dist/jquery.js", "./node_modules/bootstrap/dist/js/bootstrap.js" ] }, }, } }}, "defaultProject": "expense-manager" }
Here,
scripts option is used to include JavaScript library.
Step 4: Create a new service named AuthService to authenticate the user. The command given below will create a service with the name auth inside Services folder.
ng generate service Services/auth
On successful creation of service, you may see the below output on Angular CLI −
CREATE src/app/Services/auth.service.spec.ts (363 bytes) CREATE src/app/Services/auth.service.ts (142 bytes)
Step 5: Open AuthService and include below code:
import { Injectable } from '@angular/core'; import { Observable, of, BehaviorSubject } from 'rxjs'; import { tap, delay } from 'rxjs/operators'; @Injectable({ providedIn: 'root' }) export class AuthService { // Track login state with BehaviorSubject private isUserLoggedInSubject = new BehaviorSubject<boolean>(false); constructor() { // Only initialize sessionStorage on the client-side (browser) if (typeof window !== 'undefined' && window.sessionStorage) { const storedLoginState = sessionStorage.getItem('isUserLoggedIn') === 'true'; this.isUserLoggedInSubject.next(storedLoginState); } } login(userName: string, password: string): Observable<boolean> { const isLoggedIn = userName === 'admin' && password === 'admin'; if (typeof window !== 'undefined' && window.sessionStorage) { sessionStorage.setItem('isUserLoggedIn', isLoggedIn ? 'true' : 'false'); } // Update the BehaviorSubject with new login state this.isUserLoggedInSubject.next(isLoggedIn); return of(isLoggedIn).pipe( delay(1000), tap(val => console.log("Is User Authentication successful: " + val)) ); } logout(): void { if (typeof window !== 'undefined' && window.sessionStorage) { sessionStorage.removeItem('isUserLoggedIn'); } // Update the BehaviorSubject to false when logged out this.isUserLoggedInSubject.next(false); } // Expose the login status as an observable get isUserLoggedIn$(): Observable<boolean> { return this.isUserLoggedInSubject.asObservable(); } }
Here,
We have written two methods, login and logout.
The purpose of the login method is to validate the user and if the user successfully validated, it stores the information in localStorage and then returns true.
Authentication validation is that the user name and password should be admin.
We have not used any backend. Instead, we have simulated a delay of 1s using Observables.
The purpose of the logout method is to invalidate the user and removes the information stored in localStorage.
Step 6: Create a login component using below command −
ng generate component login
Following output will be produced on running the above code −
CREATE src/app/login/login.component.html (21 bytes) CREATE src/app/login/login.component.spec.ts (608 bytes) CREATE src/app/login/login.component.ts (242 bytes) CREATE src/app/login/login.component.css (0 bytes)
Step 7: Open LoginComponent and update the existing code with the below code −
import { Component, OnInit } from '@angular/core'; import { FormGroup, FormControl, ReactiveFormsModule } from '@angular/forms'; import { AuthService } from '../Services/auth.service'; import { Router } from '@angular/router'; @Component({ selector: 'app-login', standalone: true, imports: [ReactiveFormsModule], templateUrl: './login.component.html', styleUrl: './login.component.css' }) export class LoginComponent implements OnInit { userName: string = ""; password: string = ""; formData!: FormGroup; constructor(private authService : AuthService, private router : Router) { } ngOnInit() { this.formData = new FormGroup({ userName: new FormControl("admin"), password: new FormControl("admin"), }); } onClickSubmit(data: any) { this.userName = data.userName; this.password = data.password; console.log("Login page: " + this.userName); console.log("Login page: " + this.password); this.authService.login(this.userName, this.password) .subscribe( data => { console.log("Is Login Success: " + data); if(data) this.router.navigate(['/expenses']); }); } }
Here,
Used reactive forms.
Imported AuthService and Router and configured it in constructor.
Created an instance of FormGroup and included two instance of FormControl, one for user name and another for password.
Created a onClickSubmit to validate the user using authService and if successful, navigate to expense list.
Step 8: Open LoginComponent template and include below template code.
<div class="container"> <div class="row"> <div class="col-lg-12 text-center" style="padding-top: 20px;"> <div class="container box" style="margin-top: 10px; padding-left: 0px; padding-right: 0px;"> <div class="row"> <div class="col-12" style="text-align: center;"> <form [formGroup]="formData" (ngSubmit)="onClickSubmit(formData.value)" class="form-signin"> <h2 class="form-signin-heading">Please sign in</h2> <label for="inputEmail" class="sr-only">Email address</label> <input type="text" id="username" class="form-control" formControlName="userName" placeholder="Username" required autofocus> <label for="inputPassword" class="sr-only">Password</label> <input type="password" id="inputPassword" class="form-control" formControlName="password" placeholder="Password" required> <button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button> </form> </div> </div> </div> </div> </div> </div>
Here, we created a reactive form and designed a login form. And, attached the onClickSubmit method to the form submit action.
Step 9: Open LoginComponent CSS file and include below CSS Code.
.form-signin { max-width: 330px; padding: 15px; margin: 0 auto; } input { margin-bottom: 20px; }
Here, some styles are added to design the login form.
Step 10: Create a logout component using below command −
ng generate component logout
You may see the below output −
CREATE src/app/logout/logout.component.html (22 bytes) CREATE src/app/logout/logout.component.spec.ts (615 bytes) CREATE src/app/logout/logout.component.ts (246 bytes) CREATE src/app/logout/logout.component.css (0 bytes)
Step 11: Open LogoutComponent and include below code.
import { Component, OnInit } from '@angular/core'; import { AuthService } from '../Services/auth.service'; import { Router } from '@angular/router'; @Component({ selector: 'app-logout', standalone: true, imports: [], templateUrl: './logout.component.html', styleUrl: './logout.component.css' }) export class LogoutComponent implements OnInit { constructor(private authService : AuthService, private router: Router) { } ngOnInit() { this.authService.logout(); this.router.navigate(['/']); } }
Here,
- Used logout method of AuthService.
- Once the user is logged out, the page will redirect to home page (/).
Step 12: Create a guard using below command −
ng generate guard authenticate
On running the above command, Angular CLI will ask "Which type of guard would you like to create?" Choose canActivate.
CREATE src/app/authenticate.guard.spec.ts (510 bytes) CREATE src/app/authenticate.guard.ts (141 bytes)
Step 13: Open authenticateGuard and include below code −
import { Injectable } from '@angular/core'; import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router, UrlTree } from '@angular/router'; import { AuthService } from './Services/auth.service'; @Injectable({ providedIn: 'root' }) export class authenticateGuard implements CanActivate { constructor(private authService: AuthService, private router: Router) {} canActivate( next: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean | UrlTree { let url: string = state.url; return this.checkLogin(url); } checkLogin(url: string): true | UrlTree { console.log("Url: " + url); // Check if sessionStorage is available (only in the browser) if (typeof window !== 'undefined' && window.sessionStorage) { let val = sessionStorage.getItem('isUserLoggedIn'); // Check if the value is 'true' if (val === "true" && val != null) { // If the user is already logged in and trying to access the login page, redirect to /expenses if (url === "/login") { return this.router.parseUrl('/expenses'); } else { return true; // User is allowed to proceed } } else { // If the user is not logged in, redirect to /login return this.router.parseUrl('/login'); } } // In case sessionStorage isn't available (for SSR) return this.router.parseUrl('/login'); } }
Here,
- checkLogin will check whether the localStorage has the user information and if it is available, then it returns true.
- If the user is logged in and goes to login page, it will redirect the user to expenses page
- If the user is not logged in, then the user will be redirected to login page.
Step 14: Let's add a new component in our application. User will be redirected to this page on successful login.
ng generate component ExpenseEntryList
The output is as follows −
CREATE src/app/expense-entry-list/expense-entry-list.component.html (34 bytes) CREATE src/app/expense-entry-list/expense-entry-list.component.spec.ts (687 bytes) CREATE src/app/expense-entry-list/expense-entry-list.component.ts (292 bytes) CREATE src/app/expense-entry-list/expense-entry-list.component.css (0 bytes)
Here, the command creates the ExpenseEntryList Component and add the necessary code by default.
Step 15: Create a ExpenseEntry interface within src/app/expense-entry-list.component.ts file. Then, add a method named getExpenseEntries() to return list of expense entry (mock items) in ExpenseEntryListComponent. Also, declare a local variable, expenseEntries and load the mock list of expense entries.
import { CommonModule } from '@angular/common'; import { Component } from '@angular/core'; export interface ExpenseEntry { id: number; item: string; amount: number; category: string; location: string; spendOn: Date; createdOn: Date; } @Component({ selector: 'app-expense-entry-list', standalone: true, imports: [CommonModule], templateUrl: './expense-entry-list.component.html', styleUrl: './expense-entry-list.component.css' }) export class ExpenseEntryListComponent { getExpenseEntries() : ExpenseEntry[] { let mockExpenseEntries : ExpenseEntry[] = [ { id: 1, item: "Pizza", amount: Math.floor((Math.random() * 10) + 1), category: "Food", location: "Mcdonald", spendOn: new Date(2020, 4, Math.floor((Math.random() * 30) + 1), 10, 10, 10), createdOn: new Date(2020, 4, Math.floor((Math.random() * 30) + 1), 10, 10, 10) }, { id: 1, item: "Pizza", amount: Math.floor((Math.random() * 10) + 1), category: "Food", location: "KFC", spendOn: new Date(2020, 4, Math.floor((Math.random() * 30) + 1), 10, 10, 10), createdOn: new Date(2020, 4, Math.floor((Math.random() * 30) + 1), 10, 10, 10) }, { id: 1, item: "Pizza", amount: Math.floor((Math.random() * 10) + 1), category: "Food", location: "Mcdonald", spendOn: new Date(2020, 4, Math.floor((Math.random() * 30) + 1), 10, 10, 10), createdOn: new Date(2020, 4, Math.floor((Math.random() * 30) + 1), 10, 10, 10) }, { id: 1, item: "Pizza", amount: Math.floor((Math.random() * 10) + 1), category: "Food", location: "KFC", spendOn: new Date(2020, 4, Math.floor((Math.random() * 30) + 1), 10, 10, 10), createdOn: new Date(2020, 4, Math.floor((Math.random() * 30) + 1), 10, 10, 10) }, { id: 1, item: "Pizza", amount: Math.floor((Math.random() * 10) + 1), category: "Food", location: "KFC", spendOn: new Date(2020, 4, Math.floor((Math.random() * 30) + 1), 10, 10, 10), createdOn: new Date(2020, 4, Math.floor((Math.random() * 30) + 1), 10, 10, 10) }, ]; return mockExpenseEntries; } title: string =""; expenseEntries!: ExpenseEntry[]; constructor() { } ngOnInit() { this.title = "Expense Entry List"; this.expenseEntries = this.getExpenseEntries(); } }
Step 16: Open the template file, src/app/expense-entry-list/expense-entry-list.component.html and show the mock entries in a table.
<!-- Page Content --> <div class="container"> <div class="row"> <div class="col-lg-12 text-center" style="padding-top: 20px;"> <div class="container" style="padding-left: 0px; padding-right: 0px;"> <div class="row"> <div class="col-sm" style="text-align: left;"> {{ title }} </div> <div class="col-sm" style="text-align: right;"> <button type="button" class="btn btn-primary">Edit</button> </div> </div> </div> <div class="container box" style="margin-top: 10px;"> <table class="table table-striped"> <thead> <tr> <th>Item</th> <th>Amount</th> <th>Category</th> <th>Location</th> <th>Spent On</th> </tr> </thead> <tbody> <tr *ngFor="let entry of expenseEntries"> <th scope="row">{{ entry.item }}</th> <th>{{ entry.amount }}</th> <td>{{ entry.category }}</td> <td>{{ entry.location }}</td> <td>{{ entry.spendOn | date: 'short' }}</td> </tr> </tbody> </table> </div> </div> </div> </div>
Here,
Used bootstrap table. table and table-striped will style the table according to Boostrap style standard.
Used ngFor to loop over the expenseEntries and generate table rows.
Step 17: Open src/app/app.routes.ts and update below code −
import { Routes } from '@angular/router'; import { LoginComponent } from './login/login.component'; import { LogoutComponent } from './logout/logout.component'; import { authenticateGuard } from './authenticate.guard'; import { ExpenseEntryListComponent } from './expense-entry-list/expense-entry-list.component'; export const routes: Routes = [ { path: 'login', component: LoginComponent }, { path: 'logout', component: LogoutComponent }, { path: 'expenses', component: ExpenseEntryListComponent, canActivate: [authenticateGuard]}, {path: ' ', redirectTo: '/login', pathMatch: 'full'} ];
Here,
- Imported LoginComponent and LogoutComponent.
- Imported authenticateGuard.
- Created routes, login and logout to access LoginComponent and LogoutComponent.
- Add new option canActivate for ExpenseEntryListComponent.
Step 18: Open AppComponent template and add two login and logout link.
<nav class="navbar navbar-expand-lg navbar-dark bg-dark static-top"> <div class="container"> <a class="navbar-brand" href="#">{{ title }}</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarResponsive"> <ul class="navbar-nav ml-auto"> <li class="nav-item active"> <a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a> </li> <li class="nav-item"> <a class="nav-link" href="#">Report</a> </li> <li class="nav-item"> <a class="nav-link" href="#">Add Expense</a> </li> <li class="nav-item"> <a class="nav-link" href="#">About</a> </li> <li class="nav-item"> <div *ngIf="isUserLoggedIn; else isLogOut"> <a class="nav-link" routerLink="/logout">Logout</a> </div> <ng-template #isLogOut> <a class="nav-link" routerLink="/login">Login</a> </ng-template> </li> </ul> </div> </div> </nav> <router-outlet></router-outlet>
Step 19: Open AppComponent and update below code −
import { Component } from '@angular/core'; import { RouterOutlet } from '@angular/router'; import { ExpenseEntryListComponent } from './expense-entry-list/expense-entry-list.component'; import { LoginComponent } from './login/login.component'; import { LogoutComponent } from './logout/logout.component'; import { AuthService } from './Services/auth.service'; import { CommonModule } from '@angular/common'; @Component({ selector: 'app-root', standalone: true, imports: [RouterOutlet, ExpenseEntryListComponent, LoginComponent, LogoutComponent, CommonModule], templateUrl: './app.component.html', styleUrl: './app.component.css' }) export class AppComponent { title = 'Angular Authentication'; isUserLoggedIn: any = false; router: any; constructor(private authService: AuthService) {} ngOnInit() { // Subscribe to the isUserLoggedIn observable from AuthService this.authService.isUserLoggedIn$.subscribe(status => { this.isUserLoggedIn = status; console.log("Is User Logged In: ", this.isUserLoggedIn); }); } logout(): void { // Trigger logout in AuthService this.authService.logout(); // Redirect to the homepage after logout this.router.navigate(['/']); } }
Here, we have added the logic to identify the user status so that we can show login/logout functionality.
Step 20: Start the application using following command −
ng serve
Enter admin as username and password and then, click submit. The application process the login and redirects the user to expense list page as shown below −

Finally, your can click logout and exit the application.