Angular 15 – Using canActivate Auth Guards with Practical Examples

In this comprehensive guide, you will learn about Auth Guards in Angular 15 with practical examples of Students applications. In this tutorial series, we will cover all 4 important types of Auth Guards we generally find useful in our application including CanActivate, CanActivateChild, CanDeactivate and CanLoad with examples and detailed implementation steps. Note: In latest Angular 15,…

By.

•

min read

In this comprehensive guide, you will learn about Auth Guards in Angular 15 with practical examples of Students applications.

In this tutorial series, we will cover all 4 important types of Auth Guards we generally find useful in our application including CanActivate, CanActivateChild, CanDeactivate and CanLoad with examples and detailed implementation steps.

Note: In latest Angular 15, you will see this warning message ”

‘CanActivate’ is deprecated.ts(6385)

index.d.ts: The declaration was marked as deprecated here.
(alias) interface CanActivate
import CanActivate

After upgrading to the latest Angular 15 version, you have noticed that the warning saying canActivate interface is deprecated. You can find our Auth Guard implementation tutorial for previous versions here.

 

What are Auth Guards and Why they are used?

Auth Guards provided by Angular that are used to control behaviour during navigation to and from various routes in the application.

Routes are used to define public and private paths in the application that help a user to navigate from one component/ module to another.

Auth Guards as the name sounds act as a gatekeeper, determining whether a user can access a specific route based on conditions such as authentication status or user permissions.

 

How Auth Guard Implementation has Changed in Anguar 15?

Angular version 15 introduced a new syntax for creating route guards that do not require the use of interfaces.

According to official Angular docs, we can create a custom functional class that will inject the and Auth Service and Router service to control the navigational behaviour behind our Guards.

 

Let’s jump into the practical implementation of our canActivate class in a sample Students application. In this Students app, a user can only be allowed to view Students details, if it is logged in. Else the navigation will redirect to the Login page.

 

How to Implement canActivate Auth Guards in Angular App?

Follow these quick steps to start implementing Auth guards in your Angular project:

 

Setting up the Angular Project

First, let’s create a new Angular project using the Angular CLI:

ng new angular-auth-guards-example
cd angular-auth-guards-example

Creating Required Component

For our student’s app, we will create a few of the required components, that will help us to easy demonstrate the required scenario.

Execute the following generate commands one by one to create the required components:

ng generate component student-list
ng generate component student-details
ng generate component login

 

Create Auth Guard Function and Service Class

Next, we will create a guard and a service that will help to authenticate route navigation for our application.

Execute the following command to create them quickly:

ng generate service auth/auth
ng generate guard auth/auth

 

This is how the project directory will look after creating all the files including components, guard and service for our Student’s application:

 

Update Auth Guard and Service

Thereafter, we will update the authGuard and <span >AuthService</span>code. Open the auth.guard.ts and auth.service.ts files and update then as below:

~angular-guards-app\src\app\auth\auth.guard.ts

import { inject } from '@angular/core';
import { Router } from '@angular/router';

import { AuthService } from './auth.service';

export const authGuard = () => {
  const authService = inject(AuthService);
  const router = inject(Router);

  if (authService.isLoggedIn) {
    return true;
  }

  // Redirect to the login page
  return router.parseUrl('/login');
};

Above code defines a custom authGuard function that checks whether the user is logged in and returns a boolean value or a URL tree.

The inject function is used to inject an instance of AuthService and Router into the authGuard function.

If the AuthService indicates that the user is logged in, the function returns true, allowing the navigation to continue. Otherwise, it returns a URL tree that redirects the user to the login page.

This custom authGuard function can be used in the Angular router configuration to protect routes that require authentication.

 

~angular-guards-app\src\app\auth\auth.service.ts

import { Injectable } from '@angular/core';

import { Observable, of } from 'rxjs';
import { tap, delay } from 'rxjs/operators';

@Injectable({
  providedIn: 'root',
})
export class AuthService {
  isLoggedIn = false;

  // store the URL so we can redirect after logging in
  redirectUrl: string | null = null;

  login(): Observable<boolean> {
    return of(true).pipe(
      delay(1000),
      tap(() => (this.isLoggedIn = true))
    );
  }

  logout(): void {
    this.isLoggedIn = false;
  }
}

This is the service called AuthService that provides methods for simulating user authentication in an Angular application.

The service has the following properties and methods:

  • isLoggedIn: a boolean flag that indicates whether the user is currently authenticated or not.
  • redirectUrl: a string that stores the URL that the user was trying to access before being redirected to the login page.
  • login(): Returns an Observable that simulates the login process. The method sets the isLoggedIn flag to true after a delay of 1 second using the delay() operator from RxJS, and logs the user in using the tap() operator from RxJS.
  • logout(): a method that sets the isLoggedIn flag to false, effectively logging the user out of the application.

This service provides a simple way to handle user authentication in an Angular application, without the need for an actual authentication server or database. It can be used as a starting point for building more advanced authentication systems.

 

Update App Routing Module

Next, we will set up the Application routing module that will take in out authGuard to handle the navigation logic. Open the app-routing.module.ts file and update it with the following code:

// src/app/app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { StudentListComponent } from './student-list/student-list.component';
import { StudentDetailsComponent } from './student-details/student-details.component';
import { LoginComponent } from './login/login.component';
import { authGuard } from './auth/auth.guard';

const routes: Routes = [
  { path: '', redirectTo: '/students', pathMatch: 'full' },
  { path: 'students', component: StudentListComponent },
  {
    path: 'student/:id',
    component: StudentDetailsComponent,
    canActivate: [authGuard],
  },
  { path: 'login', component: LoginComponent },
  { path: '**', redirectTo: '/students' },
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule],
})
export class AppRoutingModule {}

Update Components Class and Templates

After completing the heavy load, now we will update the classes and HTML templates of the components we created.

Login Component:

<!-- src/app/login/login.component.html -->
<h2>Login</h2>
<button (click)="login()">Log in</button>
// src/app/login/login.component.ts
import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { AuthService } from '../auth/auth.service';

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.scss'],
})
export class LoginComponent {
  constructor(private authService: AuthService, private router: Router) {}

  login(): void {
    this.authService.login().subscribe(() => {
      if (this.authService.isLoggedIn) {
        const redirectUrl = this.authService.redirectUrl
          ? this.authService.redirectUrl
          : '/students';
        this.router.navigate([redirectUrl]);
      }
    });
  }
}

 

Student List Component:

<!-- src/app/student-list/student-list.component.html -->
<h2>Student List</h2>
<ul>
    <li *ngFor="let student of students">
        <a [routerLink]="['/student', student.id]">{{ student.name }}</a>
    </li>
</ul>
// src/app/student-list/student-list.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-student-list',
  templateUrl: './student-list.component.html',
  styleUrls: ['./student-list.component.scss'],
})
export class StudentListComponent {
  students = [
    { id: 1, name: 'Student 1' },
    { id: 2, name: 'Student 2' },
    { id: 3, name: 'Student 3' },
  ];
}

 

Student Details Component:

<!-- src/app/student-details/student-details.component.html -->
<h2>Student Details</h2>
<div *ngIf="student">
    <p>ID: {{ student.id }}</p>
    <p>Name: {{ student.name }}</p>
</div>
// src/app/student-details/student-details.component.ts
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';

@Component({
  selector: 'app-student-details',
  templateUrl: './student-details.component.html',
  styleUrls: ['./student-details.component.scss'],
})
export class StudentDetailsComponent implements OnInit {
  student: any;

  constructor(private route: ActivatedRoute) {}

  ngOnInit(): void {
    const id = Number(this.route.snapshot.paramMap.get('id'));
    this.student = { id, name: `Student ${id}` };
  }
}

 

Update App Component

Finally, we will add the links with Login/ Logout button with router-outlet to show the required components using routing.

App Component:

<!-- src/app/app.component.html -->
<header>
  <nav class="navbar navbar-expand-lg navbar-light bg-light">
    <div class="container">
      <a class="navbar-brand" routerLink="/">App</a>
      <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"
        aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
      </button>
      <div class="collapse navbar-collapse" id="navbarNav">
        <ul class="navbar-nav">
          <li class="nav-item">
            <a class="nav-link" routerLink="/students">Student List</a>
          </li>
          <li class="nav-item" *ngIf="!authService.isLoggedIn">
            <a class="nav-link" routerLink="/login">Login</a>
          </li>
          <li class="nav-item" *ngIf="authService.isLoggedIn">
            <button class="btn btn-link nav-link" (click)="logout()">Logout</button>
          </li>
        </ul>
      </div>
    </div>
  </nav>
</header>
<main class="container mt-3">
  <router-outlet></router-outlet>
</main>
// src/app/app.component.ts
import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { AuthService } from './auth/auth.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
})
export class AppComponent {
  constructor(public authService: AuthService, private router: Router) {}

  logout(): void {
    this.authService.logout();
    this.router.navigate(['/']);
  }
}

Make sure you have the following in your app.module.ts file:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { StudentListComponent } from './student-list/student-list.component';
import { StudentDetailsComponent } from './student-details/student-details.component';
import { LoginComponent } from './login/login.component';

@NgModule({
  declarations: [
    AppComponent,
    StudentListComponent,
    StudentDetailsComponent,
    LoginComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

 

Run Application

Now we are ready to run and test our application. Execute the npm start or ng serve command in the terminal to start the webserver open the application on http://localhost:4200/

Using canActivate Auth Guards with Practical Examples
Angular 15 – Using canActivate Auth Guards

 

 

Conclusion

We have successfully created an Angular application that demonstrates the use of the canActivate Auth Guard to protect certain routes. By implementing an AuthService to manage user authentication status and redirecting unauthenticated users to the Login page, we’ve ensured that only authenticated users can access protected routes which is the Student Details page here.

You can further extend this project by integrating real-world authentication providers, adding role-based access control, or implementing other guards, such as canLoad or canActivateChild, to enhance the security of your application.

Leave a Reply

Your email address will not be published. Required fields are marked *