Today we're going to secure our angular application using route guards and jwt. We'll first declare a service to handle the mundane things and then a AuthGuard
which implements CanActivate
.
Before we get started you'll need to install @auth0/angular-jwt
with an npm install @auth0/angular-jwt
.
The AuthGuard
The AuthGuard
is responsible for indicating whether or not a route should be accessible. This is configured in your routes declaration (further below). When a route is loaded it calls the canActivate
method of our AuthGuard
and will only route the user if true
.
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router';
import { Injectable } from '@angular/core';
import { AuthenticationService } from '@matthewdavis.io/ngsoa-api';
@Injectable()
export class AuthGuard implements CanActivate {
public constructor(private router: Router) {
}
public canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
if (AuthenticationService.isLoggedIn()) {
return true;
} else {
this.router.navigate(['/login'], { queryParams: { returnUrl: state.url } });
return false;
}
}
}
The AuthenticationService
The AuthenticationService
is responsible for not only calling an http method for logging in but also checking to see if a) a "token" exists in localStorage
but b) the token hasn't expired yet.
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { JwtHelperService } from '@auth0/angular-jwt';
import { Subject } from 'rxjs';
@Injectable({ providedIn: 'root' })
export class AuthenticationService {
public static getToken(): string {
return localStorage.getItem('token');
}
public static isLoggedIn(): boolean {
const helper = new JwtHelperService();
const token: string = localStorage.getItem('token');
if (token) {
return !helper.isTokenExpired(token);
}
}
public constructor(private httpClient: HttpClient) {
}
public isLoggedIn(): boolean {
const helper = new JwtHelperService();
const token: string = localStorage.getItem('token');
if (token) {
return !helper.isTokenExpired(token);
}
}
public login(email: string, password: string): any {
localStorage.removeItem('token');
let subject: Subject<RequestResult<any> | boolean> = new Subject();
this.post<any>(`users/login`, {
email,
password
}).subscribe((result: any) => {
if(result) {
subject.next(result);
}
});
return subject;
}
public logout() {
console.log('AutenticationService.logout()');
this.clear();
location.href = '/login';
}
public clear(): void {
localStorage.removeItem('token');
}
}
Routing Configuration
Now we are ready to configure our route(s) to use canActivate
by passing an array containing our AuthGuard
Class.
canActivate
will also apply to all children route(s) if present.
...
@NgModule({
imports: [
CommonModule,
RouterModule.forRoot([
{
path: 'profile',
component: ProfileComponent,
canActivate: [ AuthGuard ],
children: [
...
]
}
])
]
})
...