🙅‍♂️Authentication guard with NgRX

What are Route Guards?

Angular’s route guards are interfaces which can tell the router whether or not it should allow navigation to a requested route. They make this decision by looking for a true or false return value from a class which implements the given guard interface.

There are five different types of guards and each of them is called in a particular sequence. The router’s behavior is modified differently depending on which guard is used. The guards are:

  • CanActivate

  • CanActivateChild

  • CanDeactivate

  • CanLoad

  • Resolve

The service injects AuthService and Router and has a single method called canActivate. This method is necessary to properly implement the CanActivate interface.

The canActivate method returns a boolean indicating whether or not navigation to a route should be allowed. If the user isn’t authenticated, they are re-routed to some other place, in this case a route called /login.

Our guard:

import { Injectable } from "@angular/core";
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree } from "@angular/router";
import { select, Store } from "@ngrx/store";
import { Observable } from "rxjs";
import { tap } from "rxjs/internal/operators/tap";
import { AppState } from "../reducers";
import { isLoggedIn } from "./auth.selectots";

@Injectable()
export class AuthGuard implements CanActivate {
    constructor(
        private store: Store<AppState>,
        private route: Router) { }
    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
        return this.store.pipe(
            select(isLoggedIn),
            tap(isLogged => {
                if (!isLogged) {
                    this.route.navigateByUrl('/login')
                }
            })
        )
    }
}

Then we should need to inject our guard in our module.ts providers:

import { ModuleWithProviders, NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { LoginComponent } from './login/login.component';
import { MatCardModule } from "@angular/material/card";
import { MatInputModule } from "@angular/material/input";
import { RouterModule } from "@angular/router";
import { ReactiveFormsModule } from "@angular/forms";
import { MatButtonModule } from "@angular/material/button";
import { StoreModule } from '@ngrx/store';
import { AuthService } from "./auth.service";
import { authReducer } from './reducers';
import { AuthGuard } from './auth.guard';

@NgModule({
    imports: [
        CommonModule,
        ReactiveFormsModule,
        MatCardModule,
        MatInputModule,
        MatButtonModule,
        RouterModule.forChild([{ path: '', component: LoginComponent }]),
        StoreModule.forFeature('auth', authReducer)
    ],
    declarations: [LoginComponent],
    exports: [LoginComponent]
})
export class AuthModule {
    static forRoot(): ModuleWithProviders<AuthModule> {
        return {
            ngModule: AuthModule,
            providers: [
                AuthService,
                AuthGuard // HERE
            ]
        }
    }
}

And finally, we need to add our guard in our routes:

const routes: Routes = [
  {
    path: 'courses',
    loadChildren: () => import('./courses/courses.module').then(m => m.CoursesModule),
    canActivate: [AuthGuard] // This is an array because we can add multiple guards
  },
  {
    path: '**',
    redirectTo: '/'
  }
];

Last updated