CPCODELAB
Angular

Route Guards: Protecting Navigation

10 min read

Why Route Guards?

Route guards let you run logic before Angular activates or deactivates a route. The most common use case is authentication: redirect unauthenticated users to the login page before they can see protected content.

Functional Guards (Angular 15+)

Modern Angular favours functional guards — plain functions (or arrow functions) rather than classes implementing CanActivate. A guard returns true to allow navigation, false to block it, or a UrlTree to redirect.

ts
// auth.guard.ts
import { inject } from '@angular/core';
import { CanActivateFn, Router } from '@angular/router';
import { AuthService } from '../services/auth.service';

export const authGuard: CanActivateFn = (route, state) => {
  const auth = inject(AuthService);
  const router = inject(Router);

  if (auth.isLoggedIn()) {
    return true;
  }

  // Preserve the intended URL so we can redirect after login
  return router.createUrlTree(['/login'], {
    queryParams: { returnUrl: state.url }
  });
};
ts
// app.routes.ts
import { Routes } from '@angular/router';
import { authGuard } from './guards/auth.guard';

export const routes: Routes = [
  { path: '', loadComponent: () => import('./home/home.component').then(m => m.HomeComponent) },
  { path: 'login', loadComponent: () => import('./login/login.component').then(m => m.LoginComponent) },
  {
    path: 'dashboard',
    canActivate: [authGuard],
    loadComponent: () => import('./dashboard/dashboard.component').then(m => m.DashboardComponent)
  },
  {
    path: 'admin',
    canActivate: [authGuard, adminGuard],   // multiple guards — all must pass
    loadChildren: () => import('./admin/admin.routes').then(m => m.ADMIN_ROUTES)
  }
];

Other Guard Types

  • canActivate — runs before activating the route
  • canActivateChild — runs before activating any child route
  • canDeactivate — runs before leaving a route (e.g. unsaved form warning)
  • canMatch — runs before the router even tries to match the route (replaces canLoad)
  • resolve — pre-fetches data before the component is created

canDeactivate receives the component instance as its first argument, so the guard can call a method like component.hasUnsavedChanges() to decide whether to warn the user before navigation.

Ready to test yourself?
Practice Angular— quiz & coding exercises