Home » Coding » Angular » Angular authentication – Allow routes to signed in users only using guards

Angular authentication – Allow routes to signed in users only using guards

Angular authentication using guards

When building a website, in a lot of situations, you will have to create an authentication and authorization system in order to allow access to specific sections only to some of your users. For example, unauthenticated users shouldn’t be able to access the page to modify the user profile. Another situation would be to secure an administration panel, where only one group of users is allowed.

Angular provides a lot of features and has a lot of concepts. They’re well explained in the documentation, but some are hard to find, and you might not know what they are used for until you already know what they’re used for, it’s a vicious circle.

One of those features is part of the Angular router: route guards. They allow you to apply some verification to routes, before the user can call it.

Initial setup

In any case, you will need a service that will be usable by your other components and that will check whether your user is authenticated. Here is the minimal interface that you need:

export interface AuthService {

	isAuthenticated(): boolean;

}

I am intentionally leaving the implementation outside of the scope of this tutorial, but I plan on writing a dedicated one on how to authenticate your users on your API from an Angular frontend.

Usually this service will need to make some calls to your backend to authenticate your user, and store an authentication token on the frontend to remember that the user is logged in.

A solution that you can put in place if your backend support it is to use OAuth (if you are using a framework to make your website, it probably does!). In one of my websites I then used the Angular library angular-oauth2-oidc to implement the authentication layer.

A not so good solution

An easy solution to the problem of making sure that users are authenticated, and that you might have used, is to check directly in the component, and redirect if needed.

@Component({
	selector: 'app-user-profile',
	templateUrl: './user-profile.component.html',
	styleUrls: ['./user-profile.component.css']
})
export class UserProfileComponent implements OnInit {

    constructor(
        private authService: AuthService,
        private router: Router
    ) {
        // ... Whatever your constructor needs to do
	}

	ngOnInit() {
		if (!this.authService.isAuthenticated()) {
            this.router.navigateByUrl("/login");
        }
    }
    
}

It is a simple solution, but it has multiple major issues:

  1. You need to put the code checking for authentication in every single one of your components,
  2. If you change your logic for authentication, you need to edit all of the components that have authentication,
  3. If you have to add authorization (permissions) on top of the authentication, your code in each component becomes complex.

Using route guards to authenticate and authorize users

As we’ve seen in the previous part, having your authentication and authorization code in each component in not a scalable solution. Fortunately, we can make use of the router guards of the Angular router. This feature allows you to specify conditions to check if a user can access specific endpoints in your application.

The AuthGuard

A guard is composed of a single method canActivate, where you will implement your logic verifying if the user is authorized to access the specified route. Here is an example of the authentication guard I use in my Angular-based websites:

import {Injectable} from '@angular/core';
import {CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router} from '@angular/router';
import {Observable} from 'rxjs/Observable';

@Injectable()
export class AuthGuard implements CanActivate {

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

	canActivate(next: ActivatedRouteSnapshot,
	            state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
		if (this.authService.isAuthenticated()) {
			return true;
		}

		this.router.navigateByUrl("/login");

		return false;
	}
}

You can see that in the constructor I inject the AuthService from earlier, and also the Angular router. You are free to inject anything you need, just like in any component.

As mentioned, the canActivate part is where my logic is, so I simply call isAuthenticated() on the authentication service, and return true if the user is connected. From there, the framework will automatically allow the user to access the protected page.

On contrary, if the user isn’t authenticated, I return false, but also redirect him to the login page of my website. This part of the logic depends on you and what you want to do when an unauthenticated user tries to access a protected page. Maybe you just want to display an error message, instead of redirecting him.

Registering the guard to secure endpoints

In my guard, I don’t specify which URLs the user has access to or not, this is instead done directly in the definition of your routes, in the AppRoutingModule that you should have. To secure an endpoint, you simply have to add another key called canActivate, with the guard as value, on each of your endpoints:

const routes: Routes = [
	{ path: '', component: HomeComponent },
    { path: 'contact', component: ContactComponent },
    
    { path: 'profile', component: UserProfileComponent, canActivate: [ AuthGuard ] }
];

@NgModule({
	imports: [ RouterModule.forRoot(routes) ],
	exports: [ RouterModule ]
})
export class AppRoutingModule { }

I do not specify anything for my homepage and my contact form components, because they should be accessible by anyone, but the user profile is secured and can only be accessed by a logged in user!

Going further

You have many possibilities to improve you guard, or even create new ones. If you take again a look at the AppRoutingModule, you will see that canActivate is an array, which means it can accept multiple guards.

An example would be to use guards for authorization on top of authentication, to allow certain endpoints only to the administrators of your website. You would have a similar guard to the authentication one, but it would check if the user is an administrator before allowing access.

Another possibility, when redirecting your users, is to include the URL where they come from, in order to redirect them there once they finished logging in. To do this, simply access the variable state.url in your guard, and pass it as a query param to your login component!


This concludes this new tutorial on Angular and authentication. Angular guards are a very powerful feature that will make your code cleaner and more maintainable, so don’t hesitate to leverage them.

I would also encourage you, when using a framework, to read each of the sections of the documentation, because you might uncover new features that you didn’t know about before. You can also read the section of my blog dedicated to Angular tutorials!

Leave a Reply

Your email address will not be published. Required fields are marked *