Route Guard is an injectable service which implements one of the special guards’ interfaces and it tells the Router whether or not it should navigate a user to a route by returning ‘true’ or ‘false’, or if you need to perform some asynchronous operation (e.g verify user id and rights on the server) you can return either Observable or a Promise and the router will wait it’s resolving to true or false.

Here are the Angular Guards interfaces available:

  • CanActivate - prevents access to a route
  • CanActivateChild - prevents access to a child route
  • CanDeactivate - prevents navigation away from a route
  • Resolve - helps fetching necessary data before navigating to a route
  • CanLoad - prevents navigation to a module loaded asynchronously

Basic implementation

As we are going to prevent unauthorized navigation to some protected routes we will use CanActivate guard interface. Let’s try it out:

JavaScript

        import { Injectable } from '@angular/core';
import { Router, CanActivate } from '@angular/router';

@Injectable()
export default class CanActivateGuard implements CanActivate {
  constructor() {}

  canActivate() {
    console.info('Navigating to a protected route...');
    return true;
  }
}
      

Here we created a class implementing CanActivate interface so we must implement canActivate() method where we return either true or false.

Next, declare your new guard in the router module and specify canActivate option for your protected route:

JavaScript

        import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import PublicPage from './pages/public';
import ProtectedPage from './pages/protected';
import CanActivateGuard from './services/can-activate-guard.service';

const appRoutes: Routes = [
  { path: 'public', component: PublicPage },
  {
    path: 'protected',
    component: ProtectedPage,
    canActivate: [CanActivateGuard],
  },
];

@NgModule({
  imports: [
    RouterModule.forRoot(appRoutes),
  ],
  providers: [
    CanActivateGuard,
  ],
  exports: [
    RouterModule,
  ],
})
export default class AppRouterModule {}
      

Now when you try opening the ‘/protected’ route you will see the message 'Navigating to a protected route...', and then Angular will render the ProtectedPage component because our guard returned ‘true’. Try to change the value to ‘false’ and see what will happen.

Asynchronous Guards

If you are going to implement an authentication system you might find this article helpful. There I explain how to use JSON Web Tokens (JWT).

In this section we’ll send request to server with the token of a user trying to access a protected route, then if the server will return response with the status 200 (OK) - we return ‘true’ (allow access), otherwise we navigate the user to ‘/login’ route asking him to log in to the system before accessing the protected route, and return false.

The guard looks simple:

JavaScript

        import { Injectable } from '@angular/core';
import { Router, CanActivate } from '@angular/router';
import axios from 'axios';
import clientStorage, { STORAGE_KEY } from './clientStorage';

@Injectable()
export default class CanActivateGuard implements CanActivate {
  constructor(private router: Router) {}

  canActivate() {
    const token = clientStorage.get(STORAGE_KEY.AUTH_TOKEN);

    return axios
      .post('/api/v1/user/validate', { token })
      .then(response => {
        if (response.status === 200) {
          return true;
        }

        this.router.navigate(['/login']);
        return false;
      })
      .catch(() => {
        this.router.navigate(['/login']);
        return false;
      });
  }
}
      

Angular router will wait until the server response is fulfilled and the returned promise is resolved with the value either ‘true’ or ‘false’.