Routing
Guards
Master Angular Route Guards, covering canActivate, canDeactivate, canMatch, functional guards, and authentication protection patterns.
1. Learning Objectives
In this lesson, you will master Angular route guards. By the end of this topic, you will be able to:
- Explain the purpose and lifecycle of route guards.
- Implement
canActivateguards to protect routes from unauthorized access. - Implement
canDeactivateguards to prevent navigation away from unsaved forms. - Use
canMatchto conditionally match routes based on runtime conditions. - Write modern functional guards using the
CanActivateFnpattern.
2. Overview
Route guards are functions or classes that the Angular Router calls before or during navigation. They act as checkpoints that decide whether a user is allowed to enter a route, leave a route, or load a route's children. Guards return a boolean, a UrlTree (for redirects), or an Observable/Promise resolving to either.
3. Why This Topic Matters
Route guards are critical for application security and user experience:
- Access Control: Without guards, any user could type a protected URL (like
/admin/dashboard) directly into the browser and access the page, even if they are not authenticated. Guards intercept navigation and redirect unauthorized users to a login page. - Preventing Data Loss: If a user is editing a long form and accidentally clicks a navigation link, they lose all their work. A
canDeactivateguard prompts them with a confirmation dialog before leaving the page.
4. Real-World Analogy
Think of route guards like **security checkpoints at a building entrance**:
- canActivate (Entry Security Guard): A guard standing at the door who checks your ID badge before letting you enter a restricted floor. If you don't have the right clearance, you are redirected to the lobby (login page).
- canDeactivate (Exit Security Guard): A guard who stops you before you leave a secure room, asking "Are you sure you want to leave? You have documents on the desk that haven't been filed yet." This prevents accidental data loss.
- canMatch (Receptionist Routing): A receptionist who checks your role before deciding which elevator bank to send you to. Admins go to the executive elevator, regular employees go to the standard one.
5. Core Concepts
Angular provides several guard types for different navigation phases:
| Guard Type | When It Runs | Return Values |
|---|---|---|
| canActivate | Before a route is activated (entered). | boolean | UrlTree | Observable | Promise |
| canDeactivate | Before a route is deactivated (left). | boolean | UrlTree | Observable | Promise |
| canMatch | Before the router even matches the route definition. | boolean | UrlTree | Observable | Promise |
| canActivateChild | Before any child route of a parent is activated. | boolean | UrlTree | Observable | Promise |
6. Syntax & API Reference
Modern Angular uses functional guards (plain functions) instead of class-based guards. Below is a functional canActivate guard:
Applying Guards to Routes
7. Visual Diagram
This diagram displays the guard evaluation flow during navigation:
8. Live Example — Full Working Code
Below is a functional canDeactivate guard that prevents navigation away from unsaved form changes:
9. Interactive Playground
Try It Yourself Challenges:
- Create a role-based guard that only allows users with the "admin" role to access certain routes.
- Test what happens when the canDeactivate guard returns
false.
10. Common Mistakes
| Mistake | Why it happens | Wrong | Correct |
|---|---|---|---|
| Guard returns void instead of boolean | Forgetting to return a value from the guard function. TypeScript allows implicit void returns, but the Router interprets undefined as a falsy value, blocking all navigation. |
if (isAuth) { /* no return */ } |
return isAuth ? true : router.createUrlTree(['/login']) |
| Client-side only security | Relying solely on Angular guards for security. Guards only prevent client-side navigation; they do not protect API endpoints. A user can bypass guards by calling the API directly. | Guard only on frontend |
Guard on frontend + server-side auth middleware |
11. Best Practices
- Use functional guards: Prefer the modern functional guard pattern (
CanActivateFn) over class-based guards. They are simpler, require less boilerplate, and work well with theinject()function. - Return UrlTree for redirects: Instead of manually calling
router.navigate()and returningfalse, return aUrlTreefrom the guard. This lets Angular handle the redirect atomically and avoids race conditions. - Always implement server-side authorization: Route guards are a UI convenience, not a security measure. Always validate access on the server side in your API endpoints.
- Compose multiple guards: You can apply multiple guards to a single route. All guards must return
truefor navigation to proceed. Use this to separate concerns (e.g. one guard for authentication, another for role-based access).
12. Browser Compatibility/Requirements
Route guards are implemented in TypeScript and execute within the Angular framework's navigation lifecycle. They have no browser-specific requirements and work consistently across all modern browsers.
13. Interview Questions
Q1: What is the difference between canActivate and canMatch?
Answer: canActivate runs after the router has already matched the route and determines whether to activate (render) it. canMatch runs earlier, during the route matching phase, and determines whether the route should even be considered as a match. If canMatch returns false, the router skips the route entirely and tries the next one in the array.
Q2: Why should guards return a UrlTree instead of calling router.navigate()?
Answer: Returning a UrlTree lets Angular handle the redirect atomically as part of the navigation cycle. Calling router.navigate() manually creates a separate, concurrent navigation that can cause race conditions. The UrlTree approach is the recommended pattern for redirect guards.
14. Debugging Exercise
The guard blocks all navigation even for authenticated users. Identify the bug:
Diagnosis: Inside the if block that checks authentication, the guard logs a message but does not return true. The function falls through to the redirect statement, redirecting all users (including authenticated ones) to the login page.
Fixed guard:
15. Practice Exercises
Exercise 1: Build a role-based access system
Create an AuthService with a getUserRole() method that returns a role string ("admin", "editor", or "viewer"). Write a guard factory function that accepts allowed roles as parameters and blocks users whose role is not in the list.
16. Scenario-Based Challenge
The Multi-Guard Checkout Flow Challenge:
An e-commerce checkout page requires two guards: one to verify the user is authenticated, and another to verify the shopping cart is not empty. Write both functional guards and apply them to the checkout route. If the user is not authenticated, redirect to login. If the cart is empty, redirect to the products page.
17. Quick Quiz
Q1: What should a canActivate guard return to redirect the user to a different route?
A) false
B) A UrlTree created by router.createUrlTree()
C) A string path like '/login'
Answer: B — Guards should return a UrlTree for redirects, allowing Angular to handle the navigation atomically.
18. Summary & Key Takeaways
- Route guards intercept navigation to protect routes and prevent data loss.
- Use
canActivateto protect routes from unauthorized access andcanDeactivateto prevent leaving unsaved work. - Prefer functional guards (
CanActivateFn) over class-based guards for simplicity. - Return
UrlTreefor redirects instead of callingrouter.navigate()manually. - Always pair client-side guards with server-side authorization checks.
19. Cheat Sheet
| Guard Type | Purpose |
|---|---|
canActivate |
Checks before a route is entered (authentication, authorization). |
canDeactivate |
Checks before leaving a route (unsaved changes confirmation). |
canMatch |
Controls whether a route definition is matched at all. |