I've been building Angular applications for quite a while, and I'm recently updating my book series for Angular 17.

A Route Guard is a way to run some code when a route is requested. This code allows you to approve, or deny a user access to the route. It is common to use these as part of securing your app.

It is pretty common to need to access a Service Provider inside your Route Guard, and today I'm gonna talk about how to do that.

Route Guards with Classes

In earlier versions of Angular, Route Guards were created as Classes. Something like this:

view plain print about
1import { Injectable } from '@angular/core';
2import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot, UrlTree } from '@angular/router';
3import { Observable } from 'rxjs';
4
5@Injectable({
6 providedIn: 'root'
7})
8export class AuthGuard implements CanActivate {
9
10 constructor() {}
11
12 canActivate(
13 route: ActivatedRouteSnapshot,
14 state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
15 return true;
16 }
17
18}

This Guard does nothing, just returning true. If you needed to access a service inside the AuthGuard, you can inject it in the constructor:

view plain print about
1constructor(private myCustomService: MyCustomService){}

And inside the guard you can reference it:

view plain print about
1if (this.myCustomService.someValidationCheck()) {
2 return true;
3} else {
4 return false;
5}

Everything works great. However, in Angular 17 the default AuthGuard is not implemented as a class.

Auth Guards as Constants

In Angular 17 Auth Guards are implemented as Constants, which point to a function:

view plain print about
1import {CanActivateFn, Router} from '@angular/router';
2
3export const authGuard: CanActivateFn = (route, state) =>
{
4 return true;
5};

That was new to me, and I'm not sure if this was added to Angular 16 or 17. I'm converting an app and wondered, how do we get a service?

Angular has released a new way to inject services into classes; and this can be used for functions also. That is the new Inject function:

view plain print about
1const myCustomService: MyCustomService = inject(MyCustomService);

It took me a while to figure this out, which is I'm writing the blog post. Add a similar line above to your guard function, then you can perform a similar check to the class based guard:

view plain print about
1if (myCustomService.someValidationCheck()) {
2 return true;
3} else {
4 return false;
5}

Magic!