Building a secure Angular application means more than just hiding UI elements. I've seen applications where routes were "protected" by hiding navigation links, but users could still access protected routes by typing URLs directly. That's not securityโthat's security theater. Route Guards are Angular's way of actually protecting routes at the framework level.
Route Guards are interfaces that control navigation to and from routes. They can check authentication status, verify user permissions, prevent navigation when there are unsaved changes, and even prefetch data before a route activates. They're essential for building secure, user-friendly Angular applications.
What are Angular Route Guards?
Angular Route Guards provide:
- CanActivate - Control access to routes (authentication/authorization)
- CanDeactivate - Prevent navigation away from routes (unsaved changes)
- CanLoad - Prevent lazy-loaded modules from loading
- Resolve - Prefetch data before route activation
- Security - Framework-level route protection
- User Experience - Prevent data loss and improve performance
CanActivate Guard
Protect routes with authentication and authorization:
import { Injectable } from '@angular/core';
import { CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { AuthService } from '../auth/auth.service';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
@Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
constructor(
private authService: AuthService,
private router: Router
) {}
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<boolean> | Promise<boolean> | boolean {
return this.authService.isAuthenticated.pipe(
map(isAuthenticated => {
if (!isAuthenticated) {
localStorage.setItem('returnUrl', state.url);
this.authService.Logout();
this.router.navigate(['/login']);
return false;
}
return true;
})
);
}
}
// Use in routes
const routes: Routes = [
{
path: 'business',
canActivate: [AuthGuard],
loadChildren: () => import('./business/business.module').then(m => m.BusinessModule)
}
];
CanDeactivate Guard
Prevent navigation with unsaved changes:
import { Injectable } from '@angular/core';
import { CanDeactivate } from '@angular/router';
import { Observable } from 'rxjs';
export interface CanComponentDeactivate {
canDeactivate: () => Observable<boolean> | Promise<boolean> | boolean;
}
@Injectable({
providedIn: 'root'
})
export class CanDeactivateGuard implements CanDeactivate<CanComponentDeactivate> {
canDeactivate(
component: CanComponentDeactivate
): Observable<boolean> | Promise<boolean> | boolean {
return component.canDeactivate ? component.canDeactivate() : true;
}
}
// Component implementation
export class BusinessFormComponent implements CanComponentDeactivate {
form: FormGroup;
isDirty: boolean = false;
canDeactivate(): boolean {
if (this.form.dirty && !this.isDirty) {
return confirm('You have unsaved changes. Do you want to leave?');
}
return true;
}
}
Best Practices
- Use CanActivate for authentication/authorization
- Use CanDeactivate for unsaved changes
- Use CanLoad for lazy-loaded modules
- Use Resolve to prefetch data
- Implement proper error handling
- Store return URLs for redirects
๐ Read the Complete Guide
This is just a brief overview! The complete guide on my blog includes:
- โ Role-Based Guards - Authorization with user roles
- โ CanLoad Guard - Prevent lazy module loading
- โ Resolve Guard - Prefetch data before route activation
- โ Multiple Guards - Combining guards for complex scenarios
- โ Guard Testing - Complete testing strategies
- โ Advanced Patterns - Custom guard implementations
- โ Real-world examples from production applications
๐ Read the full article with all code examples here
What's your experience with Angular Guards? Share your tips in the comments! ๐
For more Angular guides, check out my blog covering Routing, Services, HTTP Client, and more.
Top comments (0)