Angular Route Guards For Authorization In A Web And Mobile Application

You’re about to release your new Angular web app. It’s a photo sharing site and you want to test it, so you send a link to it to your hacker sister. She’s always messing with your stuff and she found out the URL to your admin page you added to your web app. Before you know it, she’s flushed your database using a button on that admin page that you didn’t restrict access to. Not a problem when using development data - but I’m sure your users wouldn’t be any too keen on a service where they lost all of their data. Let’s fix that

Component Checks

The most basic way to restrict a user’s access to any given page is to use logic that will run at the load time of the component and redirect the user if needed. Given Angular’s lifecycle hooks, we can use ngOnInit in order to do so.

This code sample is pretty straightforward - on loading the component, let’s go ahead and check that the user is allowed to see the page, if not - let’s move them to somewhere they are allowed to see. You could even add a snackbar to let them know that they’re trying to access something they shouldn’t, maybe move them to a login page? It’s fairly customizable.

This works perfectly fine if there’s a single route you’d like to restrict users from being able to see, but perhaps you’d like to lockdown an entire module’s routes (or just a route with child routes) or there are many different routes you’d like to protect in a similar way. Of course, you could always copy and paste the code we’ve made before, but Angular actually provides a much easier, cleaner way of doing so.

Introducing: Route Guards

In essence, a route guard is simply a check to tell if you’re allowed to view a page or not. It can be added to any route using canActivate (a fairly verbose property, I’d say) with a custom interface that follows Angular’s CanActivate API. The most simplistic example of a router guard is as follows:

As you can see from the typing of canActivate, Angular is fairly lenient with what you need to return in order to let a user to access the page or not - it accepts a Promise or Observable of a boolean or even just a boolean itself as a return value. This guard has limited value currently, because it always returns true regardless of any parameters or changes. However, if we replace the canActivate method with something a little more useful, we can easily add back the functionality our old ngOnInit had:

Tada! We suddenly have the same logic as before! We can now remove the ngOnInit from the previously added route, and keep things just as secure as before! Because we can return an Observable, we can even use Observablepipes like so:

Of course, it might not be the best bet to add this logic in a guard, but it’s still representative of what you’re capable of doing inside of a guard.

Children Guarding

When I first learned about this, I thought it was the coolest thing in the world. I started adding it to all of my routes. Next thing I knew, I was adding it to all my routes I wanted protected in some form or another.

This isn’t too bad alone - but when you have hundreds of routes on a large scale project, this easily becomes unmanageable. I also had times when I wanted to add additional security to a route’s children, for example a dashboard page that included some admin routes that I wanted to lock down. This is where child guards come into play.

Child guards do exactly what you think they would. They add an additional guard for children. They use a similar API as canActivate, and the reference to that API can be found here. So, if I were to add the following guard to my child routes:

However, I’m sure you’re wondering what happens if you apply a canActivate alongside a canActivateChild. If you were to change the code so the canActivate runs a console.log('This is the canActivate!') and your routes were to look like this:

And accessed the list route, your console would output ‘This is the canActivate!’ and then ‘This child was activated!’. Of course, this has limited application when making an empty route without a component to load (that’s not a child), but it’s massively helpful when you have a component in the parent route such as this:

[
{
path: '',
canActivate: [AuthenticationGuard],
canActivateChild: [AuthorizationGuard],
children: [
{ path: 'admin', component: AdminComponent },
]
}
];
// NOT SHOWN: AuthenticationGuard and AuthorizationGuard. Just pretend they're code that checks what you think they would, based on the names (remember, authentication is if the user is who they say they are [AKA logged in]; authorization is making sure they have the right access [AKA if they're admin])

In this example, when you access the '' path, you’ll make sure the user is authenticated, but doesn’t care about authorization. However, when you access a child of that path (in this example, 'admin'), it will check both authentication AND authorization.

Route Data

But let’s say that I wanted to be able to change my child route based on information that I’ve stored about that particular route. For example, I typically layout my breadcrumbs by using a data property on my routes like such:

Because the first argument to canActivateChild is an ActivatedRouteSnapshot, you can grab any of the methods or properties from the API from the routes that are currently being called. However, something you’ll probably want to keep in mind is that this will occur once for every single child route being called.

Lazy Loading

Because lazy loading using loadChildren is still considered a child route, all of the same rules from Children Guarding still apply. However, there are more tricks that are available for lazy loaded routes that are not otherwise available.

Can Load

The API for canLoad looks very similar to what we’ve seen before with canActivate and canActivateChild.

In this example, if you access the '' route, only the AuthenticationGuard would be called. Meanwhile, if you accessed the 'otherfeature' route, you would load the AuthenticationGuard, THEN call the AuthorizationGuard. What order would you think the guards would load for the 'feature' route? The answer might be a little more tricky than you expect.

The answer? canLoad runs first. Before AuthenticationGuard and before AuthorizationGuard. It also, unlike the other two, prevents the entire loading of the route. The advantage here is that you can stop the loading of a lazy-loaded route before doing any checks you’d want to run to prevent. This would increase performance greatly in situations where you’d block the loading of a page and it would be much more secure. After canLoad runs, then the other two run in order as they would before

Wrap Up

Just like anything else, an Angular Router Guard is a tool. It has many uses that are really only restricted by how you’re able to utilize that tool. You’re able to do service calls, logic changes, and more in order to restrict access to a page. However, it’s not a one-tool-fits-all solution. There will be times that a resolver might be able to help better, or sometimes even component logic might fit your use-case better. That being said, Guards are incredibly helpful when the time comes to use them

Corbin Crutchley

Corbin Crutchley is a fan of anything tech related. Always looking for new ways to learn and grow, he spends most days tinkering on a machine of some kind. He has experience with Python, Angular, React, and NativeScript. Corbin cares passionately about documentation and always wants to contribute back.