Dec 4, 2025

Angular CanActivate Guard: Protect Your Routes Like a Pro

Tags

Hey there! Remember when I built that user dashboard for my blog project and realised anyone could just type in the admin URL and see all the sensitive stuff? That panicked moment taught me a valuable lesson—routes need protection! That's exactly what Angular's CanActivate guard does: it acts like a bouncer at a club, checking if users have the right credentials before letting them into protected areas of your app.


canactivate-guard


The Problem I Faced (And Solved)


I had a dashboard page at /admin where writers could manage posts on www.codevichar.com. But without protection, anyone could navigate there directly. I needed a way to check if they're logged in before the page even loads. CanActivate was perfect—it runs right before route activation and can redirect unauthorized users.


How I Built My CanActivate Guard


Let me walk you through the exact implementation I used. This is fresh code from my project—no copy-pasting from tutorials!


Step 1: Create the Auth Service (The Brain)


First, I needed a simple service to track login status. Nothing fancy, just localStorage simulation for demo:

// auth.service.ts
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';

@Injectable({ providedIn: 'root' })
export class AuthService {
  private loggedInSubject = new BehaviorSubject<boolean>(false);
  loggedIn$ = this.loggedInSubject.asObservable();

  login(email: string, password: string): boolean {
    // Simulate API call
    if (email === 'admin@codevichar.com' && password === 'codevichar123') {
      localStorage.setItem('token', 'fake-jwt-token');
      this.loggedInSubject.next(true);
      return true;
    }
    return false;
  }

  logout(): void {
    localStorage.removeItem('token');
    this.loggedInSubject.next(false);
  }

  isLoggedIn(): boolean {
    return !!localStorage.getItem('token');
  }
}


Step 2: Build the CanActivate Guard (The Bouncer)


Now the guard itself. It checks the auth status and redirects if needed:


// admin.guard.ts
import { Injectable } from '@angular/core';
import { CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { AuthService } from './auth.service';
import { Observable } from 'rxjs';
import { map, tap } from 'rxjs/operators';

@Injectable({ providedIn: 'root' })
export class AdminGuard implements CanActivate {
  constructor(
    private authService: AuthService,
    private router: Router
  ) {}

  canActivate(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Observable<boolean> {
    return this.authService.loggedIn$.pipe(
      tap(_isLoggedIn => {
        if (!_isLoggedIn) {
          // Redirect to login with return URL
          this.router.navigate(['/login'], {
          queryParams: { returnUrl: state.url }
          });
        }
      }),
      map(isLoggedIn1 => isLoggedIn1)
    );
  }
}



Notice the tap operator? It lets me redirect without affecting the boolean return value. Clean!


Step 3: Wire It to Routes


Super simple—just add canActivate to your protected route:


// app-routing.module.ts
const routes: Routes = [
  { path: '', component: HomeComponent },
  { path: 'login', component: LoginComponent },
  {
    path: 'admin',
    component: AdminDashboardComponent,
    canActivate: [AdminGuard]
  },
  { path: '**', redirectTo: '' }
];



Step 4: Login Component (Bonus)


Here's the matching login page that uses the auth service:


// login.component.ts
export class LoginComponent implements OnInit {
  email = '';
  password = '';
  error = '';

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

  onLogin() {
    if (this.authService.login(this.email, this.password)) {
      this.router.navigate(['/admin']);
    } else {
      this.error = 'Wrong credentials recieved!';
    }
  }
}



What Makes This Setup Awesome


This CanActivate pattern saved my dashboard from unwanted visitors! Here’s what I love about it:

  • Early Protection: Blocks access before the component even initialises
  • Smart Redirects: Sends users to login with their intended destination preserved
  • Async Ready: Works with Observables/Promises for real API calls
  • Multiple Guards: Stack several (auth + role + feature flag)
  • Clean Components: No auth logic cluttering your pages

Pro tip: Always return UrlTree from Router for programmatic redirects instead of just navigating—it cancels navigation cleanly.

When I first implemented this for codevichar.com, it felt like adding a proper lock to my digital house. No more heart attacks about open admin pages!


EmoticonEmoticon