Screenshot for a Login form

Introduction

In this write-up, I want to take you through how I managed to implement/configure Auth0 with Angular 8 to have my Authentication module up and running.

I have had opportunities to work on several software products and I noticed that all most all projects I have worked on and those out there have at least one thing in common and that is user authentication and authorization. I have not had an opportunity to implement/configure Auth0 with Angular 8.

Auth0 is a platform that provides authentication and authorization as a service. This simply means that once you configure Auth0 with Angular 8 or any other frontend framework, you only need to do some simple setup to have authentication and authorization part of your application finished. This implies you have more time to focus on implementing the core functionality of your application and you can get started right away. Join me and let’s configure Auth0 with Angular 8 together.

Glossary

Angular: A platform for building mobile and desktop web applications.
Auth0: A platform used to rapidly integrate authentication and authorization for web, mobile, and legacy applications so you can focus on the core business of your application.
Authentication: Is the process of verifying who a user is.
Authorization: Is the process of verifying what the user can access.

Requirements

Node.JS: Required to run Angular on your machine.
Text editor: Use a text editor you are comfortable with.
Internet: You need internet to link the Angular app with Auth0.
Basic Javascript, typescript and Angular knowledge.

Step One – Create an app on Auth0

First things first, Access Auth0 home page and sign-up using any of the options availed to you, this should be quick, easy and explicit. On successful sign-up, you will be able to see the application dashboard. 

Click the create application button on the right side of the screen to get started with creating a new application.

Screenshot of Auth0 Dashboard after login highlighting create application button

On clicking the create application button, a module box will pop up prompting you to input the name of the application and the application type. Enter your desired name then choose Single Page Web Applications as the application type and click create.

Screenshot of a module box with a form to create a new application

Step Two – App configurations

On the side-navigation panel, navigate to Applications, click on the application you have just created to get to its settings.

Configure Callback URLs: This is a URL in the application where Auth0 redirects the user after they have been authenticated. Let’s set our call back URL to be https://localhost:4200

Configure Logout URLs: This is a URL in the application that Auth0 can return to after the user has been logged out of the authorization server. Let’s use https://localhost:4200

Configure Allowed Web Origins: This is to whitelist the application URL such that it’s allowed access to the Auth0 server. I am setting this to https://localhost:4200 as well.

Screen recording for setting application configurations

Step Three – Create an Angular application

To create an Angular application you need to have the Angular CLI installed on your machine. This helps you to generate all the boilerplate for the new Angular application with minimum effort. Run the following command to install Angular CLI on your machine.

npm install -g @angular/cli

Generate a new Angular application by running the following command from your filesystem wherever you’d like your application to be created.

ng new Angular8-auth0

When asked “Would you like to use Angular routing?”, select y (yes).
When prompted “Which stylesheet format would you like to use?”, select CSS.
Once the project has been created, open the Angular8-auth0 a folder in your favorite code editor.

Open your terminal and navigate to the project folder, install the Auth0 SDK using NPM.

npm install @auth0/auth0-spa-js

The command will install the auth0 SDK to the application dependencies.

Step four – Add the Authentication service

At this point, we create an authentication service to manage authentication with Auth0. We can generate a new Angular service by executing the following script in the terminal.

ng g s auth

Lucky enough we don’t have to type all the code to handle the interaction between the auth service we have just created and the Auth0 SDK, It has been provided for by Auth0 already. I have the snippet so just copy and paste it in the service you have just generated. Then go ahead to copy the domain and client_id provided to you in the application settings section. Update the domain and client_id values in the snippet provided.

import { Injectable } from '@angular/core';
import createAuth0Client from '@auth0/auth0-spa-js';
import Auth0Client from '@auth0/auth0-spa-js/dist/typings/Auth0Client';
import { from, of, Observable, BehaviorSubject, combineLatest, throwError } from 'rxjs';
import { tap, catchError, concatMap, shareReplay } from 'rxjs/operators';
import { Router } from '@angular/router';

@Injectable({
  providedIn: 'root'
})
export class AuthService {
  // Create an observable of Auth0 instance of client
  auth0Client$ = (from(
    createAuth0Client({
      domain: "Add your domain here",
      client_id: "Add your client id here",
      redirect_uri: "http://localhost:8000"
    })
  ) as Observable<Auth0Client>).pipe(
    shareReplay(1), // Every subscription receives the same shared value
    catchError(err => throwError(err))
  );
  // Define observables for SDK methods that return promises by default
  // For each Auth0 SDK method, first ensure the client instance is ready
  // concatMap: Using the client instance, call SDK method; SDK returns a promise
  // from: Convert that resulting promise into an observable
  isAuthenticated$ = this.auth0Client$.pipe(
    concatMap((client: Auth0Client) => from(client.isAuthenticated())),
    tap(res => this.loggedIn = res)
  );
  handleRedirectCallback$ = this.auth0Client$.pipe(
    concatMap((client: Auth0Client) => from(client.handleRedirectCallback()))
  );
  // Create subject and public observable of user profile data
  private userProfileSubject$ = new BehaviorSubject<any>(null);
  userProfile$ = this.userProfileSubject$.asObservable();
  // Create a local property for login status
  loggedIn: boolean = null;

  constructor(private router: Router) {
    // On initial load, check authentication state with authorization server
    // Set up local auth streams if user is already authenticated
    this.localAuthSetup();
    // Handle redirect from Auth0 login
    this.handleAuthCallback();
  }

  // When calling, options can be passed if desired
  // https://auth0.github.io/auth0-spa-js/classes/auth0client.html#getuser
  getUser$(options?): Observable<any> {
    return this.auth0Client$.pipe(
      concatMap((client: Auth0Client) => from(client.getUser(options))),
      tap(user => this.userProfileSubject$.next(user))
    );
  }

  private localAuthSetup() {
    // This should only be called on app initialization
    // Set up local authentication streams
    const checkAuth$ = this.isAuthenticated$.pipe(
      concatMap((loggedIn: boolean) => {
        if (loggedIn) {
          // If authenticated, get user and set in app
          // NOTE: you could pass options here if needed
          return this.getUser$();
        }
        // If not authenticated, return stream that emits 'false'
        return of(loggedIn);
      })
    );
    checkAuth$.subscribe();
  }

  login(redirectPath: string = '/') {
    // A desired redirect path can be passed to login method
    // (e.g., from a route guard)
    // Ensure Auth0 client instance exists
    this.auth0Client$.subscribe((client: Auth0Client) => {
      // Call method to log in
      client.loginWithRedirect({
        redirect_uri: `${window.location.origin}`,
        appState: { target: redirectPath }
      });
    });
  }

  private handleAuthCallback() {
    // Call when app reloads after user logs in with Auth0
    const params = window.location.search;
    if (params.includes('code=') && params.includes('state=')) {
      let targetRoute: string; // Path to redirect to after login processsed
      const authComplete$ = this.handleRedirectCallback$.pipe(
        // Have client, now call method to handle auth callback redirect
        tap(cbRes => {
          // Get and set target redirect route from callback results
          targetRoute = cbRes.appState && cbRes.appState.target ? cbRes.appState.target : '/';
        }),
        concatMap(() => {
          // Redirect callback complete; get user and login status
          return combineLatest([
            this.getUser$(),
            this.isAuthenticated$
          ]);
        })
      );
      // Subscribe to authentication completion observable
      // Response will be an array of user and login status
      authComplete$.subscribe(([user, loggedIn]) => {
        // Redirect to target route after callback processing
        this.router.navigate([targetRoute]);
      });
    }
  }

  logout() {
    // Ensure Auth0 client instance exists
    this.auth0Client$.subscribe((client: Auth0Client) => {
      // Call method to log out
      client.logout({
        client_id: "Add your client id",
        returnTo: "http://localhost:4200"
      });
    });
  }

}

The service provides some basic methods, such as:
getUser$(options) – Requests user data from the SDK and accepts an options parameter, then makes the user profile data available in a local RxJS stream.
login() – Log in with Auth0.
logout() – Log out of Auth0.

With this all set and configured properly, you have an authentication module ready in a very short time so you have more time to focus on how to implement the core business logic.

So we have our authentication service configured to work with the Auth0 SDK ready, the rest is about implementing the common web components such as the navigation bar, buttons that get displayed, clicked to trigger the authentication and authorization.

Step five – Create a navigation bar component

Let us create a navigation bar that will house a button that triggers the login/signup process handled by Auth0 through our auth service. To create a component using Angular CLI, run the following script in the terminal.

ng g c components/nav-bar

That script generates a nav-bar component and inserts it into the components directory.

Open the src/app/components/nav-bar.component.ts file and replace it’s contents with the following.

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

@Component({
  selector: 'app-navbar',
  templateUrl: './nav-bar.component.html',
  styleUrls: ['./nav-bar.component.css']
})
export class NavbarComponent implements OnInit {

  // Inject Authservice 
  constructor(public auth: AuthService) { }

  ngOnInit() {
  }

}

The AuthService class has been injected into our nav-bar component through the component constructor. This will help us determine the state in which our current user is in and we use this to determine what to display on our navigation bar.

Let us configure the UI template of our nav-bar component. open nav-bar.component.html file and replace its current content with the following:

<header>
  <!-- Display this button incase the user is not logged in, hide it when user is logged in  -->
  <button (click)="auth.login()" *ngIf="!auth.loggedIn">Log In</button>
  <!--  Display this button when user is logged in and hide it not logged in  -->
  <button (click)="auth.logout()" *ngIf="auth.loggedIn">Log Out</button>
</header>

We are through with our nav-bar component, we only need to have it displayed on every page in our application. We achieve this by placing the component selector in the root component template. Open app.component.html and paste the following:

<!-- Place the nav-bar component selector on top -->
<app-navbar></app-navbar>
<router-outlet></router-outlet>

Now our nav-bar has been fully integrated with the rest of the app, feel free to try running the app by running npm start in a terminal and this should fire up the app. I added a profile component that displays user details but only accessed when a user is logged in, A user is only authorized to view his/her profile. Check out the source code for all this here.

Learning Tools

Auth0 docs
Angular docs

Learning Strategy

Being aware that most application always require a module to handle authentication and authorization, I realized that this is something that can be abstracted away by either coming up a library that developers could just plugin, do some simple configurations and the authentication module ready in just a click. I thought of coming up with such a library but then I had to first make research about any platforms that were solving a similar problem that’s when I came across Auth0, I knew about Auth0 but I was not aware exactly of what it does and what it tries to solve exactly and how it approaches the problem space. 

At first, while going through Auth0 docs everything seemed to be explicit yet when I started trying it out I realized that there were a few things I had to figure out on my own. So this tutorial should help you not to fall in the same trap I fell in.

Reflective Analysis

While taking on this challenge, I thought I would need to implement my login and sign-up frontend components so I wasted some time trying to test out the various endpoints little did I know that actually, Auth0 provides customizable login and sign-up components. As soon as I realized that, everything simply linked up. However, the option of using Auth0 API endpoints also exists. That implies you can still develop your presentation layer for authentication and let Auth0 just handle the authentication and authorization logic.

Conclusion

There we go !! everything is up and running. I hope when you get to implement your app with Angular and Auth0 everything will be very simple and quick but if that’s not the case feel free to refer to this article again or even check out the entire codebase here. Going forward, you can try implementing your Angular application with an auth module and components that consume the authentication endpoints exposed by Auth0.