Todd Motto

Todd Motto

Owner, Ultimate Angular

Angular 2 authentication with Auth0 and NodeJS
Apr 19, 2016
7 mins read
Edit post

If you’ve needed to add authentication to an AngularJS (1.x) app, you’ll have likely have had some fun and perhaps been lost at where to start. Traditional methods of session and cookie-based auth are challenging for full-on single page apps regardless of the framework or strategy you choose, so I’ve usually used JSON Web Tokens JWT for stateless authentication instead. Even when using JWTs though, there’s still a lot that needs to be kept in check. Things like hiding and showing various parts of the UI based on the user’s authentication state, attaching the JWT as an Authorization header in HTTP requests, and redirecting to the login route when a request gets rejected as being invalid.

When it comes to adding authentication to an Angular (v2+) app, we still need to think about these things, but the approach is a little different. To start, we no longer have the concept of HTTP interceptors in Angular, like we did in AngularJS, which means we need some other way of binding the user’s JWT to requests.

Implementing authentication on the front end is only half the battle though - we also need to create some backend code that checks the user’s credentials, signs tokens for them, and checks whether the token is valid when requests are made to our API endpoints. Which is a lot of work! It’s also prone to error and is something that’s really important to get right, obviously!

So, in this post we’re going to demonstrate how to handle authentication using Angular, Node.js and Auth0 which I’ve used with working on AngularJS, so this is great to be able to dive into Angular with what I’m used to. Auth0 lets us forget about most of the backend logic altogether (I’m no backend programmer) and integrates nicely with Node, so all we really need to do is make sure that our Angular app is set up to save and send JWTs. Let’s get started!

Prerequisites

If you’ve not dived much into Angular, I’ve some articles that are probably a good place to start first, bootstrapping your first app and creating your first Component.

Setup

First, you’ll need to make sure you have Angular and Node.js available, as well as a free Auth0 account (it’s free up to 7,000 active users which is plenty, though if you’re running an open source project then Auth0 is free if you drop in their logo, perks).

Before we can dive into Angular + Node, we need to configure some fake users in Auth0, so jump here if you’re following along and create some users in the management dashboard. We get a default app when we register, and this app comes with a domain and client ID which we’ll need later.

Next steps

Auth0 provides a smart login widget that we can drop into our app, so I’m going to be using that because I’m not reinventing the wheel, if you want to create your own then just use the API.

Now we simply drop in the lock script into our index.html file somewhere in the <head>:

<html>
  <head>
    <script src="//cdn.auth0.com/js/lock-9.0.min.js"></script>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    ...
  </head>
  <body>...</body>
</html>

Angular Authentication Service

One question that frequents when implementing auth in Angular apps is “where does the logic go?”. Sometimes our apps will only have one location where the login is managed and other times there will be multiple locations. So we’re going to just be creating one Service to keep things simple. Now using Angular, we’re going to be creating an AuthService and mark it as @Injectable() so we can dependency inject it wherever we want:

// services/auth.service.ts
import { Injectable } from '@angular/core';

// We want to avoid any 'name not found'
// warnings from TypeScript
declare var Auth0Lock: any;

@Injectable()
export class AuthService {

 lock = new Auth0Lock('YOUR_AUTH0_CLIENT_ID', 'YOUR_AUTH0_DOMAIN');

 login() {
   this.lock.show((error: string, profile: Object, id_token: string) => {
     if (error) {
       console.log(error);
     }
     // We get a profile object for the user from Auth0
     localStorage.setItem('profile', JSON.stringify(profile));
     // We also get the user's JWT
     localStorage.setItem('id_token', id_token);
   });
 }

 logout() {
   // To log out, we just need to remove
   // the user's profile and token
   localStorage.removeItem('profile');
   localStorage.removeItem('id_token');
 }
}

Well, that was simple. Now we can inject the Service wherever we want! For instance, we might have a component with a toolbar that has Login and Logout buttons.

// components/toolbar.component.ts
import { Component } from '@angular/core';
import { AuthService } from '../services/auth.service';

@Component({
  selector: 'toolbar',
  template: `
    <div class="toolbar">
      <button (click)="auth.login()">Login</button>
      <button (click)="auth.logout()">Logout</button>
    </div>
  `,
  providers:[AuthService]
})
export class ToolbarComponent {
  constructor(private auth: AuthService) {}
  login() {
    this.auth.login();
  }
  logout() {
    this.auth.logout();
  }
}

Clicking the Login button shows us the Lock widget and we can now enter our credentials:

Our JSON Web Token and user profile are now saved in localStorage and are ready to be used in requests that go to our API:

Sending Authenticated HTTP Requests

Our JWT is stored and ready to go, but how do we actually send it in requests to the API? We can get the JWT from localStorage and attach it as a header to HTTP requests manually, or we can use Auth0’s angular2-jwt module to do this automatically, we can npm i it into our project:

npm i angular2-jwt

After we configure the module, we can inject it wherever we need and use it to send authenticated requests. Let’s say we have a component that fetches a list of users from a backend and displays them, we can import AuthHttp from angular2-jwt and subscribe to it with Rx:

// components/user-list.component.ts
import { Component, OnInit } from '@angular/core';
import { AuthHttp } from 'angular2-jwt';
import 'rxjs/add/operator/map';

interface User {
  id: number,
  name: string,
  image: string
}

@Component({
  selector: 'user-list',
  template: `
    <h2>Users</h2>
    <ul>
      <li *ngFor="user of users">
        <img [src]="user.image">
        <span>{{user.name}}</span>
      </li>
    </ul>
  `
})
export class UserListComponent implements OnInit {
  users: User[];
  constructor(private authHttp: AuthHttp) {}
  ngOnInit() {
    this.authHttp.get('//my-app.com/api/users')
      .map(res => res.json())
      .subscribe(
        users => this.users = users,
        error => console.log(error)
      );
  }
}

When we use AuthHttp instead of the regular Http module shipped with Angular, the JWT in localStorage gets attached as an Authorization header automatically. We could of course write some logic to create Headers and then attach them to each regular Http request manually, but angular2-jwt does this for us.

Middleware on the Server

We also need a server that will check for the JWT and only pass the data back if the token is valid. This can be done really easily in NodeJS with Express.

Let’s install express, express-jwt and cors:

mkdir server && cd server
npm i express express-jwt cors

Then, we can create our server and basic server-side logic:

var express = require('express');
var app = express();
var jwt = require('express-jwt');
var cors = require('cors');

app.use(cors());

// Authentication middleware provided by express-jwt.
// This middleware will check incoming requests for a valid
// JWT on any routes that it is applied to.
var authCheck = jwt({
  secret: new Buffer('YOUR_AUTH0_SECRET', 'base64'),
  audience: 'YOUR_AUTH0_CLIENT_ID'
});

var users = [
  { id: 1, name: 'Todd Motto', image: 'image-1.jpg' },
  { id: 2, name: 'Brad Green', image: 'image-2.jpg' },
  { id: 3, name: 'Igor Minar', image: 'image-3.jpg' }
];

app.get('/api/users', authCheck, function(req, res) {
  res.json(users);
});

app.listen(4000);
console.log('Listening on http://localhost:4000');

The middleware is what guards our data. We set it up on the authCheck variable using the secret key provided by Auth0, and then we apply it to the /api/users endpoint by passing it into app.get as the second argument. If the JWT that gets attached in our AuthHttp request is valid, it will pass through this middleware and our users Array will be returned.

Conditional rendering with ngIf

We can create a loggedIn method for our AuthService that can be used to conditionally hide and show various elements. For example, we would only want to show the Login button when the user is not currently authenticated, and on the flip side, we’d only want to see Logout when there’s an unexpired JWT in localStorage.

// services/auth.service.ts
import { tokenNotExpired } from 'angular2-jwt';
// ...
loggedIn(): boolean {
  return tokenNotExpired();
}
// ...

This will return true or false depending on whether the JWT in localStorage is expired or not. Now let’s apply it to our Angular template:

// components/toolbar.component.ts
import { Component } from '@angular/core';
import { AuthService } from './services/auth.service';

@Component({
  selector: 'toolbar',
  template: `
    <div class="toolbar">
      <button (click)="auth.login()" *ngIf="!auth.loggedIn()">
        Login
      </button>
      <button (click)="auth.logout()" *ngIf="auth.loggedIn()">
        Logout
      </button>
    </div>
  `
})

Logging Users Out

We’ve already composed a logout method on the AuthService, and all that it really does is remove the user’s JWT and profile from localStorage. This is all that’s really needed for logging out in a stateless scenario because, again, there’s no session saved on the server that determines the user’s authentication state.

Wrapping up

Hopefully you’ve had some decent insight into Angular authentication with JSON Web Tokens, Auth0 and Node. It’s been a pretty simple journey using Auth0 for all of this and it was awesome implementing it inside Angular!

Mar 22, 2016

Transclusion in Angular 2 with ng-content

Transclusion is an AngularJS (1.x) term, lost in the rewrite of Angular (v2+), so let’s...

Jun 3, 2016

Lifecycle hooks in Angular 1.5

Lifecycle hooks are simply functions that get called at specific points of a component’s life...