Protect Angular 7|8|9 Routes with canActivate Interface

By Digamber Rawat Last updated on
Angular 2 Route CanActivate Guard

In this tutorial, I am going to explain how you can protect Angular 7|8|9 routes with canActivate Guard for Firebase users. Route guard prevents unauthorized users to access the Angular app.

I created this small Angular 7|8|9 Firebase demo app for showing you how you can follow the best practice for Angular app’s route security. CanActivate interface provides the best example for angular app’s URL security.

I will create a simple function, this function will return true if the user is logged in. If the user is not logged in then it will return false.

Create the Route Guards

Below commands will order Angular 7|8|9 CLI to generate canActivate route guard files.

ng g guard auth
ng g guard secure-inner-pages

Generate AuthService File and Import Guards and AuthService into auth.service.ts

Create auth.service.ts file to store core logic for our app.

ng g service auth

Import route guards and auth.service.ts files within app.module.ts then inject within the providers array.

// Auth service
import { AuthService } from "./shared/services/auth.service";

// Import canActivate guards
import { AuthGuard } from "./shared/guard/auth.guard";
import { SecureInnerPagesGuard } from "./shared/guard/secure-inner-pages.guard";

@NgModule({
  declarations: [...],
  imports: [...],
  providers: [AuthService, AuthGuard, SecureInnerPagesGuard],
  bootstrap: [...]
})

src/shared/services/auth.service.ts

In this auth.service.ts file, I have mentioned the following methods.

  • Save Firebase user in localStorage
  • isLoggedIn() getter method checks whether the Firebase user is logged in or not
  • GoogleAuth() method for sign in with Google
  • SignOut() method for sign out from app Angular Firebase app
import { Injectable, NgZone } from '@angular/core';
import { auth } from 'firebase/app';
import { AngularFireAuth } from "@angular/fire/auth";
import { Router } from "@angular/router";

@Injectable({
  providedIn: 'root'
})

export class AuthService {
  userData: any;

  constructor(
    public afAuth: AngularFireAuth,
    public router: Router,  
    public ngZone: NgZone // NgZone service to remove outside scope warning
  ) {    
    // Setting logged in user in localstorage else null
    this.afAuth.authState.subscribe(user => {
      if (user) {
        this.userData = user;
        localStorage.setItem('user', JSON.stringify(this.userData));
        JSON.parse(localStorage.getItem('user'));
      } else {
        localStorage.setItem('user', null);
        JSON.parse(localStorage.getItem('user'));
      }
    })
  }

  // Returns true when user is looged in and email is verified
  get isLoggedIn(): boolean {
    const user = JSON.parse(localStorage.getItem('user'));
    return (user !== null) ? true : false;
  }

  // Sign in with Google
  GoogleAuth() {
    return this.AuthLogin(new auth.GoogleAuthProvider());
  }

  // Auth logic to run auth providers
  AuthLogin(provider) {
    return this.afAuth.auth.signInWithPopup(provider)
    .then((result) => {
       this.ngZone.run(() => {
          this.router.navigate(['user-profile']);
        })
    }).catch((error) => {
      window.alert(error)
    })
  }

  // Sign out 
  SignOut() {
    return this.afAuth.auth.signOut().then(() => {
      localStorage.removeItem('user');
      this.router.navigate(['sign-in']);
    })
  }

}

app/shared/guard/auth.guard.ts

I am going to write logic in AuthGuard class using canActivate interface method to prevent unauthorized user access. I’ll be using isLoggedIn getter method from auth.service.ts service module, this getter method will return true if the user is present in localStorage else return false if the user is null in localStorage.

CanActivate method works on the boolean result, if the user is not logged in this guard will block the unauthorized access and redirect the user to sign in page. Otherwise, it will allow the user to access the page.

import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';
import { AuthService } from "../../shared/services/auth.service";
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})

export class AuthGuard implements CanActivate {
  
  constructor(
    public authService: AuthService,
    public router: Router
  ){ }

  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
    if(this.authService.isLoggedIn !== true) {
      window.alert('Access Denied, Login is Required to Access This Page!')
      this.router.navigate(['sign-in'])
    }
    return true;
  }

}

app/shared/guard/secure-inner-pages.guard.ts

We are creating this guard to prevent users to access some pages when the user is already logged in.

import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';
import { AuthService } from "../../shared/services/auth.service";
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})

export class SecureInnerPagesGuard implements CanActivate {

  constructor(
    public authService: AuthService,
    public router: Router
  ) { }

  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
    if(this.authService.isLoggedIn) {
       window.alert("You are already signed in, access denied!");
       this.router.navigate(['user-profile'])
    }
    return true;
  }

}

Using AuthGuard in Angular 7|8|9

Below is the example of how to use auth guards in Angular routing file.

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

// Required components for which route services to be activated
import { SignInComponent } from '../../components/sign-in/sign-in.component';
import { UserProfileComponent } from '../../components/user-profile/user-profile.component';

// Import canActivate guards
import { AuthGuard } from "../../shared/guard/auth.guard";
import { SecureInnerPagesGuard } from "../../shared/guard/secure-inner-pages.guard";

// Include route guard in routes array
const routes: Routes = [
  { path: '', redirectTo: '/sign-in', pathMatch: 'full'},
  { path: 'sign-in', component: SignInComponent, canActivate: [SecureInnerPagesGuard]},
  { path: 'user-profile', component: UserProfileComponent, canActivate: [AuthGuard] },
];

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

export class AppRoutingModule { }

GitHub Project Files

GitHub Resources

I hope this tutorial has been helpful to you. If you think this tutorial has helped you then must share this tutorial with others.

You can also follow me on Twitter @ImDigamberSingh

You can also check out my detailed article on Full Firebase Authentication System with Angular 7|8|9.

Digamber Rawat
Digamber Rawat

Full stack developer with a passion for UI/UX design. I create beautiful and useful digital products to solve people’s problem and make their life easy.