Tutorial

Authentication in Angular Using Auth0 & Auth0 Lock

Published on November 21, 2017
Default avatar

By Alligator.io

Authentication in Angular Using Auth0 & Auth0 Lock

While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the ā€œreport an issueā€œ button at the bottom of the tutorial.

Authentication can be hard, and reinventing the wheel each time itā€™s needed in an app is certainly no fun. Thankfully, different services and tools can take care of the heavy lifting for us. Weā€™ve already discussed implementing authentication using Firebase, so letā€™s now explore an alternative: Auth0. Auth0 is a very powerful solution that offers all the features you would expect from an authentication provider (social logins, email/password logins, authorization rules,ā€¦)

In this post, weā€™ll be using the Auth0 Lock widget, which allows to embed a popup inside your app for authentication. You can also implement authentication on Auth0ā€™s hosted login page, in which case you may want to refer to this guide.

This post covers authentication for Angular 2+ apps.

Setup

First things first, youā€™ll need to create an Auth0 account and then create a new Single Page Web Application client.

Once your client is created, youā€™ll be able to configure the settings according to your preferences. One thing thatā€™ll be important is to add a callback URL that reflects an actual login callback route in your Angular app. Here weā€™ll create a login route, so weā€™ll add http://localhost:4200/login as our only allowed callback URL. Auth0 will redirect to it after authentication.

In your clientā€™s settings, youā€™ll also have access to the domain and client ID information. Add that information in your appā€™s environment.ts file:

environment.ts
export const environment = {
  production: false,
  auth0: {
    domain: 'your-awesome-domain.auth0.com',
    clientId: 'XXXXXXXXXXXXXXXXXXXXXXXXXXX',
    callbackURL: 'http://localhost:4200/login'
  }
};

Youā€™ll also need three additional packages in your project: auth0-js, auth0-lock and angular2-jwt. Letā€™s install them into our project using either npm or Yarn:

$ yarn add auth0-js auth0-lock angular2-jwt

# or, using npm:
$ npm install auth0-js auth0-lock angular2-jwt

Now add auth0.min.js to the list of scripts that are included in the build for your app:

.angular-cli.json
...,
"scripts": [
  "../node_modules/auth0-js/build/auth0.min.js"
],
...

Tenants

With Auth0, you can create multiple tenants to accommodate for different deployment environments (development, production, staging,ā€¦) Each tenant gets its own domain name (e.g.: my-app-dev.auth0.com and my-app.auth0.com). This way, you can create a different client for production, and all youā€™d need is to populate your production environment file with the different domain name, client id and callback URL.

Components & Routing Setup

Weā€™ll add two components to our app: a home component and a login callback component. We can use the Angular CLI to easily generate the new components:

$ ng g c home
$ ng g c login

Next, letā€™s setup a simple routing module:

app.routing.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

import { LoginComponent } from './login/login.component';
import { HomeComponent } from './home/home.component';
const routes: Routes = [
  { path: '', component: HomeComponent },
  { path: 'login', component: LoginComponent }
];

Auth Service

Letā€™s also use the Angular CLI to create an Auth service:

$ ng g s auth

At this point, youā€™ll want to make sure that your routing module is imported in your app module and that the auth service is provided by the app module as well.

Letā€™s start setting up the auth service:

auth.service.ts
import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { environment } from '../environments/environment';

import { tokenNotExpired } from 'angular2-jwt';
import Auth0Lock from 'auth0-lock';
@Injectable()
export class AuthService {
  auth0Options = {
    theme: {
      logo: '/assets/alligator-logo.svg',
      primaryColor: '#DFA612'
    },
    auth: {
      redirectUrl: environment.auth0.callbackURL,
      responseType: 'token id_token',
      audience: https://${environment.auth0.domain}/userinfo,
      params: {
        scope: 'openid profile'
      }
    },
    autoclose: true,
    oidcConformant: true,
  };
  lock = new Auth0Lock(
    environment.auth0.clientId,
    environment.auth0.domain,
    this.auth0Options
  );
  constructor(private router: Router) {
    this.lock.on('authenticated', (authResult: any) => {
      console.log('Nice, it worked!');
      this.router.navigate(['/']); // go to the home route
      // ...finish implementing authenticated
    });
this.lock.on('authorization_error', error => {
  console.log('something went wrong', error);
});  }
  login() {
    this.lock.show();
  }
  logout() {
    // ...implement logout
  }

Here are a few things to note:

  • We first define a new instance of Auth0Lock, which takes the client id, domain and a configuration object. There are plenty of configuration options available, and here on top of the required options we also added some theming options to style the lock widget.
  • In the options, we also specify what kind of data we want back using the scopes key. Here, on top of the default openid, weā€™re also interested in getting back the profile information.
  • In the serviceā€™s constructor, we listen for either the authenticated or the authorization_error events on the lock instance. The authenticated eventā€™s callback will have our logic for when an authentication is successful.
  • The login method is as easy to implement as calling the show method on our lock instance.
  • Weā€™ll have to come back and finish implementing the logout and and isAuthenticated methods.

We can now inject the auth service in our home component:

home.component.ts
import { Component } from '@angular/core';

import { AuthService } from '../auth.service';
@Component({
  selector: 'app-home',
  templateUrl: './home.component.html'
})
export class HomeComponent {

And letā€™s add login and logout buttons in to the template:

home.component.html
<button
  *ngIf="!auth.isAuthenticated()"
  (click)="auth.login()">
  Sign Up or Login
</button>

<button
  *ngIf="auth.isAuthenticated()"
  (click)="auth.logout()">
  Logout
</button>

With our basic auth service in place, the Auth0 embed is already working and we can signup or login:

Lock widget example

Profile, IsAuthenticated, Logout

Letā€™s complete our auth service implementation. For our example, weā€™ll save the JSON Web Token that Auth0 returns to local storage. That token can then be added to an Authorization header using the Bearer prefix on HTTP requests to your backend API. Itā€™ll then be the responsibility of the backend to ensure that the token is valid. Weā€™ll also get the accountā€™s profile information that we requested using scopes and save it to local storage.

First, the logic on successful authenticated events:

auth.service.ts (partial)
this.lock.on('authenticated', (authResult: any) => {
  this.lock.getUserInfo(authResult.accessToken, (error, profile) => {
    if (error) {
      throw new Error(error);
    }

localStorage.setItem('token', authResult.idToken);
localStorage.setItem('profile', JSON.stringify(profile));
this.router.navigate(['/']);

Here weā€™re calling getUserInfo on the lock instance and passing-in the access token returned from the successful authentication. getUserInfo gives us access to the profile information for the user.


isAuthenticated

Our isAuthenticated method is useful for our app to know if thereā€™s an authenticated used or not and adapt the UI in consequence.

To implement it, weā€™ll make use of angular2-jwtā€™s tokenNotExpired method. Itā€™ll return false if thereā€™s no token or if the token is expired:

isAuthenticated() {
  return tokenNotExpired();
}

Login Out

Since using JWTs for authentication is stateless, all we have to do to logout is to remove the token and profile from local storage:

auth.service.ts
logout() {
  localStorage.removeItem('profile');
  localStorage.removeItem('token');
}

šŸ”‘ And there you have it! Simple authentication for your apps.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about us


About the authors
Default avatar
Alligator.io

author

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
Ā 
1 Comments
ļ»æ

This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

I am interesting with this tutorial, is there a GitHub for this tutorial? in addition, is there any update? because this is 2017ā€™s version

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Get our biweekly newsletter

Sign up for Infrastructure as a Newsletter.

Hollie's Hub for Good

Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

Become a contributor

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

Welcome to the developer cloud

DigitalOcean makes it simple to launch in the cloud and scale up as you grow ā€” whether you're running one virtual machine or ten thousand.

Learn more
DigitalOcean Cloud Control Panel