Sep 15, 2017

In a previous post I went over how to authenticate an Angular 4 app using PHP sessions and flat files. While that is definitely a method that will work, I wanted a bit more of a robust authentication method that doesn’t require files on your server at all other than the application itself. Auth0 is a really nice service because you can use it for free and integrate it pretty seamlessly into any JavaScript app. It allows you to have users login or register with existing credentials like Google or Facebook or store their email in a database setup by Auth0.

Boilerplate JWT Auth0 Angular4

Need: Boilerplate code to enable users to authenticate for Angular 4 applications. Secure sending of authentication to APIs on other domains will be required in some cases.

Using Auth0 allows us to easily get authentication up without having to fuss with a database or server side code. I believe it is better to focus on the requirements of the application rather than worrying about doing boilerplate authentication code on both the client and server machines for everything. More info on the actual code in below sections.

JWT enables us to send the authentication to other servers. PHP can easily consume a JWT token and check it against a public key (or also generate them against the private key). Similarly, if you implement more complex REST API services on an external VPS you can use the same JWT token to validate against the additional API(s).

Demo

The demo can be found here. It is a very simple login. The credentials for this example are:

Email: example-email@acostanza.com

Password: example

You will first see this page:

This contains the login component within the router-outlet of the index component. Clicking login calls the Auth0 external login:

Login with the credentials provided above, or if you want with your Google account. You can also sign up and make your own account – but that is a feature you would typically disable on a real administrative login. Upon hitting the login button you should get the admin area:

This is the example component that is restricted with CanActivate within our Angular App. You can also see the appearance of a Log Out button in the navigation – other navigation could also be added.

High Level Overview

I started with the samples by the Auth0 team but found that on traditional hosting like Namecheap (i.e. where the only server side scripts you could really run are PHP, no Node, .Net, etc) that the samples broke because the crawlback URL wouldn’t actually resolve due to the limited server and the authentication handler method wasn’t actually called. I updated the boilerplate code to have routes restricted using CanActivate, like in the previous post, so that there can be administrative routes as well as unprotected ones. In addition, there is an index component that contains the navigation and router outlet as well as a login component that is routed when the user is not authenticated.

Full Code

The full code for this can be found on GitHub.

AuthGuard

One of the main updates to the original sample code is implementing an AuthGuard so that routes can be protected by CanActivate. Let’s see that code below:

import { Injectable } from '@angular/core';
import { Router, CanActivate } from '@angular/router';
import { AuthService } from './auth.service';

@Injectable()
export class AuthGuard implements CanActivate {
 
    constructor(private authService: AuthService, private router: Router) { }
 
    canActivate(): boolean {
		if(!this.authService.isAuthenticated()) {
			this.router.navigate(['/login']);
			return false;
		} else {
			return true;
		}
    }
	canActivateChild(): boolean {
		return this.authService.isAuthenticated();
	}
}

This time the canActivate method returns an actual boolean, rather than an Observable<boolean>.

Index Component

I created an index component that the navigation and router-outlet sit within. See below for the HTML:

<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<div class="container-fluid indx-wrapper">
<nav class="navbar navbar-default">
  <div class="container-fluid">
    <div class="navbar-header">
      <a class="navbar-brand" href="#">Example Login</a>
    </div>
	<div class="navbar-right button-wrapper">
	  <button
			class="btn btn-primary btn-margin"
			*ngIf="auth.isAuthenticated()"
			(click)="auth.logout()">
			  Log Out
		  </button>
		 </div>
  </div>
  
</nav>

  <router-outlet></router-outlet>

</div>

Within the TypeScript file we tell the index to handle authentication if there are any hash tags in the URL. This is an important update because Auth0 will callback to the main URL with the token info appended to a hashtag, i.e. #key-here. You can’t use Hash based routing because of this without some fuss, and if the routed URL is requested you will get a 404 without proper server setup. I fixed this by just redirecting the routes to the main app, but that means the hash tag would either be removed if a callback route is called or a 404 would be called without a redirect. Having the index handle the token callback fixes this:

import { Component, OnInit } from '@angular/core';
import { AuthService } from '../auth/auth.service';

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

  constructor(public auth: AuthService) { }

  ngOnInit() {
  this.auth.handleAuthentication();
  }

}

Login Component

I also wanted to have a specific component that is called when the user is not authorized. It might seem weird to call it a “login” component – but you could actually embed the auth0 login into your website and use this page to serve it, or you could have other features on the unauthorized page like links or other Angular components. For this example the HTML is quite simple:

<div class="text-center" style="width:100%">
<div class="row">
To continue please login.
</div>
<div class="row">
<button class="btn" (click)="login()">Login</button>
</div>
</div>

And the TypeScript file:

import { Component, OnInit } from '@angular/core';
import {AuthService} from "../auth/auth.service";
import { Router } from '@angular/router';
@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
   constructor(private authService: AuthService, private router: Router) {}
  login(): void {
	this.authService.login();
  }
  ngOnInit():void {
	let checkAuth = localStorage.getItem('access_token');
	if (typeof checkAuth !== 'undefined' && checkAuth !== null) {
		 this.router.navigate(['/home']);
	}
  }
}

Routes

Let’s see how you can now set up routes to your components:

const routes: Routes = [
  {path: '', component: AppComponent, canActivate: [AuthGuard]},
  {path: 'login', component:LoginComponent},
  {path: 'home', component:AppComponent,
  canActivate: [AuthGuard]},
  {path: '**', component: AppComponent}
];

All that is necessary is to call canActivate property with AuthGuard, you can also use canActivateChild like in the other authentication post to decrease the amount of typing required. There you go! I hope you find this boilerplate code useful for your application.