TL;DR: Charts create some of the most catchy sections on any business applications. A chart that updates in real time is even more catchy/useful and adds huge value to users. Here, you will see how to create real-time charts using Angular, D3, and Socket.IO. You can find the final code produced throughout this article in this GitHub repository.


With the evolution of the web, the needs of users are also increasing. The capabilities of the web in the present era can be used to build very rich interfaces. The interfaces may include widgets in the dashboards, huge tables with incrementally loading data, different types of charts and anything that you can think of. Thanks to the technologies like WebSockets, users want to see the UI updated as early as possible. This is a good problem for you to know how to deal with.

In this article, you will build a virtual market application that shows a D3 multi-line chart. That chart will consume data from a Node.js backend consisting of an Express API and a SocketIO instance to get this data in real time.

"Learn how to create real-time @Angular apps with D3 and Socket.IO"

Creating a Virtual Market Server

The demo app you are going to build consists of two parts. One is a Node.js server that provides market data and the other is an Angular application consuming this data. As stated, the server will consist of an Express API and a SocketIO endpoint to serve the data continuously.

So, to create this server and this Angular application, you will a directory to hold the source code. As such, create a new directory called virtual-market and, inside this folder, create a sub-directory called server. In a terminal (e.g. Bash or PowerShell), you can move into the server directory and run the following command:

# move into the server directory
cd virtual-market/server/

# initialize it as an NPM project
npm init -y

This command will generate the package.json file with some default properties. After initializing this directory as an NPM project, run the following command to install some dependencies of the server:

npm install express moment

Once they are installed, you can start building your server.

Building the Express API

First, create a new file called market.js inside the server directory. This file will be used as a utility. It will contain the data of a virtual market and it will contain a method to update the data. For now, you will add the data alone and the method will be added while creating the Socket.IO endpoint. So, add the following code to this file:

const marketPositions = [
  {"date": "10-05-2012", "close": 68.55, "open": 74.55},
  {"date": "09-05-2012", "close": 74.55, "open": 69.55},
  {"date": "08-05-2012", "close": 69.55, "open": 62.55},
  {"date": "07-05-2012", "close": 62.55, "open": 56.55},
  {"date": "06-05-2012", "close": 56.55, "open": 59.55},
  {"date": "05-05-2012", "close": 59.86, "open": 65.86},
  {"date": "04-05-2012", "close": 62.62, "open": 65.62},
  {"date": "03-05-2012", "close": 64.48, "open": 60.48},
  {"date": "02-05-2012", "close": 60.98, "open": 55.98},
  {"date": "01-05-2012", "close": 58.13, "open": 53.13},
  {"date": "30-04-2012", "close": 68.55, "open": 74.55},
  {"date": "29-04-2012", "close": 74.55, "open": 69.55},
  {"date": "28-04-2012", "close": 69.55, "open": 62.55},
  {"date": "27-04-2012", "close": 62.55, "open": 56.55},
  {"date": "26-04-2012", "close": 56.55, "open": 59.55},
  {"date": "25-04-2012", "close": 59.86, "open": 65.86},
  {"date": "24-04-2012", "close": 62.62, "open": 65.62},
  {"date": "23-04-2012", "close": 64.48, "open": 60.48},
  {"date": "22-04-2012", "close": 60.98, "open": 55.98},
  {"date": "21-04-2012", "close": 58.13, "open": 53.13}

module.exports = {

Now, add another file and name it index.js. This file will do all the Node.js work required. For now, you will add the code to create an Express REST API to serve the data. So, add the following code to the file index.js:

const app = require('express')();
const http = require('http').Server(app);
const market = require('./market');

const port = 3000;

app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', '*');
  res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');

app.get('/api/market', (req, res) => {

http.listen(port, () => {
  console.log(`Listening on *:${port}`);

After saving this file, you can check if everything is going well. Run the following command to start your Express REST API:

# from the server directory, run the server
node index.js

As this command starts your Node.js server on port 3000, you can visit the http://localhost:3000/api/market URL to see the market updates on the last few days.

Fake market data to show on the real-time Angular application.

Adding Socket.IO to Serve Data in Real Time

To show a real-time chart, you will need to simulate a real-time market data by updating it every 5 seconds. For this, you will add a new method to the market.js file. This method will be called from a Socket.IO endpoint that you will add to your index.js file. So, open the file market.js and add the following code to it:

const moment = require('moment');

// const marketPositions ...

let counter = 0;

function updateMarket() {
  const diff = Math.floor(Math.random() * 1000) / 100;
  const lastDay = moment(marketPositions[0].date, 'DD-MM-YYYY').add(1, 'days');
  let open;
  let close;

  if (counter % 2 === 0) {
    open = marketPositions[0].open + diff;
    close = marketPositions[0].close + diff;
  } else {
    open = Math.abs(marketPositions[0].open - diff);
    close = Math.abs(marketPositions[0].close - diff);

    date: lastDay.format('DD-MM-YYYY'),

module.exports = {

The updateMarket method generates a random number every time it is called and adds it to (or subtracts it from) the last market value to generate some randomness in the figures. Then, it adds this entry to the marketPositions array.

Now, open the index.js file, so you can create a Socket.IO connection to it. This connection will call the updateMarket method after every 5 seconds to update the market data and will emit an update on the Socket.IO endpoint to update the latest data for all listeners. In this file, make the following changes:

// ... other import statements ...
const io = require('')(http);

// ... app.use and app.get ...

setInterval(function () {
  io.sockets.emit('market', market.marketPositions[0]);
}, 5000);

io.on('connection', function (socket) {
  console.log('a user connected');

// http.listen(3000, ...

With these changes in place, you can start building the Angular client to use this.

Building the Angular Application

To generate your Angular application, you can use Angular CLI. There are two ways to do it. One is to install a local copy of the CLI globally in your machine and the other is to use a tool that comes with NPM that is called npx. Using npx is better because it avoids the need to install the package locally and because you always get the latest version. If you want to use npx, make sure that you have npm 5.2 or above installed.

Then, go back to the main directory of your whole project (i.e. the virtual-market directory) and run the following command to generate the Angular project:

npx @angular/cli new angular-d3-chart

Once the project is generated, you need to install both the D3 and Socket.IO NPM libraries. So, move to the angular-d3-chart directory and run the following command to install these libraries:

npm install d3

As you will use these libraries with TypeScript, it is good to have their typings installed. So, run the following command to install the typings:

npm i @types/d3 @types/ -D

Now that the setup process is done, you can run the application to see if everything is fine:

# from the angular-d3-chart directory
npm start

To see the default Angular application, just point your browser to the http://localhost:4200 URL.

Building a Component to Display the D3 Chart

Now that your Angular application setup is ready, you can start writing its code. First, you will add a component to display the multi-line D3 chart. Second, you will create a service to fetch the data. For now, this service will consume static data from the REST API then, in no time, you will add real-time capabilities to your app.

So, run the following command to add a file for this service:

npx ng generate service market-status

To consume the REST APIs, you need to use the HttpClient service from the HttpClientModule module. This module has to be imported into the application's module for this. As such, open the app.module.ts file and replace its code with this:

import {BrowserModule} from '@angular/platform-browser';
import {NgModule} from '@angular/core';
import {HttpClientModule} from '@angular/common/http';

import {AppComponent} from './app.component';

  declarations: [
  imports: [
  providers: [],
  bootstrap: [AppComponent]
export class AppModule {}

As you can see, the new version of this file does nothing besides adding the HttpClientModule to the imports section of the AppModule module.

Now, open the market-status.service.ts file and add the following code to it:

import {Injectable} from '@angular/core';
import {HttpClient} from '@angular/common/http';

import {MarketPrice} from './market-price';

  providedIn: 'root'
export class MarketStatusService {

  private baseUrl =  'http://localhost:3000';
  constructor(private httpClient: HttpClient) { }

  getInitialMarketStatus() {
    return this.httpClient.get<MarketPrice[]>(`${this.baseUrl}/api/market`);

This service uses the MarketPrice class to structure the data received from your backend API (baseUrl = 'http://localhost:3000'). To add this class to your project, create a new file named market-price.ts in the app folder and add the following code to it:

export  class MarketPrice {
  open: number;
  close: number;
  date: string | Date;

Now, add a new component to the application, so you can show the multi-line D3 chart. The following command adds this component:

npx ng g c market-chart

Then, open the market-chart.component.html file and replace its default content with this:

<div #chart></div>

The D3 chart will be rendered inside this <div #chart> element. As you can see, you created a local reference for the div element (#chart). You will use this reference in your component class while configuring D3.

This component will not use the MarketStatusService to fetch data. Instead, it will accept the data as input. The goal of this approach is to make the market-chart component reusable. For this, the component will have an Input field and the value to this field will be passed from the app-root component. The component will use the ngOnChanges lifecycle hook to render the chart whenever there is a change in the data. It will also use the OnPush change detection strategy to ensure that the chart is re-rendered only when the input changes.

So, open the file market-chart.component.ts and add the following code to it:

import {ChangeDetectionStrategy, Component, ElementRef, Input, OnChanges, ViewChild} from '@angular/core';
import * as d3 from 'd3';

import {MarketPrice} from '../market-price';

  selector: 'app-market-chart',
  templateUrl: './market-chart.component.html',
  styleUrls: ['./market-chart.component.css'],
  changeDetection: ChangeDetectionStrategy.OnPush
export class MarketChartComponent implements OnChanges {
  chartElement: ElementRef;

  parseDate = d3.timeParse('%d-%m-%Y');

  marketStatus: MarketPrice[];

  private svgElement: HTMLElement;
  private chartProps: any;

  constructor() { }

  ngOnChanges() { }

  formatDate() {
    this.marketStatus.forEach(ms => {
      if (typeof === 'string') { = this.parseDate(;

Now, the MarketChartComponent class has everything required to render the chart. In addition to the local reference for the div (chartElement) and the lifecycle hook, the class has a few fields that will be used while rendering the chart. The parseDate method converts string values to Date objects and the private fields svgElement and chartProps will be used to hold the reference of the SVG element and the properties of the chart respectively. These fields will be quite useful to re-render the chart.

Now, the most complex part of the tutorial. Add the following method to the MarketChartComponent class:

 buildChart() {
  this.chartProps = {};

  // Set the dimensions of the canvas / graph
  var margin = { top: 30, right: 20, bottom: 30, left: 50 },
    width = 600 - margin.left - margin.right,
    height = 270 - - margin.bottom;

  // Set the ranges
  this.chartProps.x = d3.scaleTime().range([0, width]);
  this.chartProps.y = d3.scaleLinear().range([height, 0]);

  // Define the axes
  var xAxis = d3.axisBottom(this.chartProps.x);
  var yAxis = d3.axisLeft(this.chartProps.y).ticks(5);

  let _this = this;

  // Define the line
  var valueline = d3.line<MarketPrice>()
    .x(function (d) {
      if ( instanceof Date) {
        return _this.chartProps.x(;
    .y(function (d) { console.log('Close market'); return _this.chartProps.y(d.close); });

  // Define the line
  var valueline2 = d3.line<MarketPrice>()
    .x(function (d) {
      if ( instanceof Date) {
        return _this.chartProps.x(;
    .y(function (d) { console.log('Open market'); return _this.chartProps.y(; });

  var svg =
    .attr('width', width + margin.left + margin.right)
    .attr('height', height + + margin.bottom)
    .attr('transform', `translate(${margin.left},${})`);

  // Scale the range of the data
    d3.extent(_this.marketStatus, function (d) {
      if ( instanceof Date)
        return ( as Date).getTime();
  this.chartProps.y.domain([0, d3.max(this.marketStatus, function (d) {
    return Math.max(d.close,;

  // Add the valueline2 path.
    .attr('class', 'line line2')
    .style('stroke', 'green')
    .style('fill', 'none')
    .attr('d', valueline2(_this.marketStatus));

  // Add the valueline path.
    .attr('class', 'line line1')
    .style('stroke', 'black')
    .style('fill', 'none')
    .attr('d', valueline(_this.marketStatus));

  // Add the X Axis
    .attr('class', 'x axis')
    .attr('transform', `translate(0,${height})`)

  // Add the Y Axis
    .attr('class', 'y axis')

  // Setting the required objects in chartProps so they could be used to update the chart
  this.chartProps.svg = svg;
  this.chartProps.valueline = valueline;
  this.chartProps.valueline2 = valueline2;
  this.chartProps.xAxis = xAxis;
  this.chartProps.yAxis = yAxis;

Refer to the comments added before every section in the above method to understand what the code is doing. Also, if you have any specific doubt, just leave a comment.

Now, you will have to change the ngOnChanges function (still in your MarketChartComponent class) to call this method:

ngOnChanges() {
  if (this.marketStatus) {

Now, you need to insert this component in the app-root component to see the chart. So, open the app.component.html file and replace its content with:

<app-market-chart [marketStatus]="marketStatusToPlot"></app-market-chart>

Then, you have to replace the content of the app.component.ts file with the following code:

import {Component} from '@angular/core';
import {MarketStatusService} from './market-status.service';
import {Observable} from 'rxjs';
import {MarketPrice} from './market-price';

  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
export class AppComponent {
  title = 'app';
  marketStatus: MarketPrice[];
  marketStatusToPlot: MarketPrice[];

  set MarketStatus(status: MarketPrice[]) {
    this.marketStatus = status;
    this.marketStatusToPlot = this.marketStatus.slice(0, 20);

  constructor(private marketStatusSvc: MarketStatusService) {

      .subscribe(prices => {
        this.MarketStatus = prices;

Save these changes and run the application using the ng serve command (or npm start). Now, head to the http://localhost:4200/ URL and you will see a page with a chart similar to the following image:

Showing a D3 chart with static data in an Angular application.

Adding Real-Time Capabilities to the D3 Chart

Now that you have the chart rendered on the page, you can make it receive the market updates from Socket.IO to make it real-time. To receive these updates, you need to add a listener to the Socket.IO endpoint in the market-status.service.ts file. So, open this file and replace its code with:

import {Injectable} from '@angular/core';
import {HttpClient} from '@angular/common/http';

import {MarketPrice} from './market-price';
import { Subject, from } from  'rxjs';
import * as socketio from '';

  providedIn: 'root'
export class MarketStatusService {

  private baseUrl =  'http://localhost:3000';
  constructor(private httpClient: HttpClient) { }

  getInitialMarketStatus() {
    return this.httpClient.get<MarketPrice[]>(`${this.baseUrl}/api/market`);

  getUpdates() {
    let socket = socketio(this.baseUrl);
    let marketSub = new Subject<MarketPrice>();
    let marketSubObservable = from(marketSub);

    socket.on('market', (marketStatus: MarketPrice) => {;

    return marketSubObservable;

The new method, getUpdates, does three important things:

  • it creates a manager for the Socket.IO endpoint at the given URL;
  • it creates a RxJS Subject and gets an Observable from this subject. This observable is returned from this method so consumers can listen to the updates;
  • The call to the on method on the Socket.IO manager adds a listener to the market event. The callback passed to this method is called whenever the Socket.IO endpoint publishes something new.

Now, you have to make the AppComponent class consume the getUpdates() method. So, open the app.component.ts file and modify the constructor as shown below:

constructor(private marketStatusSvc: MarketStatusService) {
    .subscribe(prices => {
      this.MarketStatus = prices;

      let marketUpdateObservable =  this.marketStatusSvc.getUpdates();  // 1
      marketUpdateObservable.subscribe((latestStatus: MarketPrice) => {  // 2
        this.MarketStatus = [latestStatus].concat(this.marketStatus);  // 3
      });  // 4

In the above snippet, the statements marked with the numbers are the new lines added to the constructor. Observe the statement labeled with 3. This statement creates a new array instead of updating the field marketStatus. This is done to let the consuming app-market-chart component know about the change when you have an update.

The last change you will need to do to see the chart working in real time is to make the flowing data hit the chart. To do this, open the market-chart.component.ts file and add the following method to the MarketChartComponent class:

updateChart() {
  let _this = this;

  // Scale the range of the data again
  this.chartProps.x.domain(d3.extent(this.marketStatus, function (d) {
    if ( instanceof Date) {

  this.chartProps.y.domain([0, d3.max(this.marketStatus, function (d) { return Math.max(d.close,; })]);

  // Select the section we want to apply our changes to

  // Make the changes to the line chart'.line.line1') // update the line
    .attr('d', this.chartProps.valueline(this.marketStatus));'.line.line2') // update the line
    .attr('d', this.chartProps.valueline2(this.marketStatus));'.x.axis') // update x axis
    .call(this.chartProps.xAxis);'.y.axis') // update y axis

The comments added in the snippet explain what you are doing in this method. Now, you have to make the ngOnChanges method call this new method. So, change the ngOnChanges() method in the MarketChartComponent class as shown below:

ngOnChanges() {
  if (this.marketStatus &&  this.chartProps) {
  } else if (this.marketStatus) {

Now, if you run the application, you will see an error on the browser console saying global is not defined.

Console error saying global is not defined.

This is because Angular CLI 6 removed the global object and SocketIO uses it. To fix this problem, add the following statement to the polyfills.ts file:

(window as any).global = window;

With this, all the changes are done. Save all your files and run the applications again. You can move into the server directory in one terminal and issue node index.js to run your backend API, then move to the angular-d3-chart directory and issue npm start to run the Angular application.

Now, if you head to (http://localhost:4200)[http://localhost:4200], you will see your nice chart with real-time data flowing into it every 5 seconds.

Real-time chart with Angular, D3, and SocketIO.

Awesome, right?

"Adding real-time capabilities to @Angular is easy with D3 and Socket.IO"

Aside: Authenticate an Angular App and Node API with Auth0

We can protect our applications and APIs so that only authenticated users can access them. Let's explore how to do this with an Angular application and a Node API using Auth0. You can clone this sample app and API from the angular-auth0-aside repo on GitHub.

Auth0 login screen


The sample Angular application and API has the following features:

  • Angular application generated with Angular CLI and served at http://localhost:4200
  • Authentication with auth0.js using a login page
  • Node server protected API route http://localhost:3001/api/dragons returns JSON data for authenticated GET requests
  • Angular app fetches data from API once user is authenticated with Auth0
  • Profile page requires authentication for access using route guards
  • Authentication service uses subjects to provide authentication and profile data to the app

Sign Up for Auth0

You'll need an Auth0 account to manage authentication. You can sign up for a free account here. Next, set up an Auth0 application and API so Auth0 can interface with an Angular app and Node API.

Set Up an Auth0 Application

  1. Go to your Auth0 Dashboard: Applications section and click the "+ Create Application" button.
  2. Name your new app and select "Single Page Web Applications".
  3. In the Settings for your new Auth0 app, add http://localhost:4200/callback to the Allowed Callback URLs.
  4. Add http://localhost:4200 to both the Allowed Web Origins and Allowed Logout URLs. Click the "Save Changes" button.
  5. If you'd like, you can set up some social connections. You can then enable them for your app in the Application options under the Connections tab. The example shown in the screenshot above uses username/password database, Facebook, Google, and Twitter.

Note: Set up your own social keys and do not leave social connections set to use Auth0 dev keys or you will encounter issues with token renewal.

Set Up an API

  1. Go to APIs in your Auth0 dashboard and click on the "Create API" button. Enter a name for the API. Set the Identifier to your API endpoint URL. In this example, this is http://localhost:3001/api/. The Signing Algorithm should be RS256.
  2. You can consult the Node.js example under the Quick Start tab in your new API's settings. We'll implement our Node API in this fashion, using Express, express-jwt, and jwks-rsa.

We're now ready to implement Auth0 authentication on both our Angular client and Node backend API.

Dependencies and Setup

The Angular app utilizes the Angular CLI. Make sure you have the CLI installed globally:

$ npm install -g @angular/cli

Once you've cloned the project on GitHub, install the Node dependencies for both the Angular app and the Node server by running the following commands in the root of your project folder:

$ npm install
$ cd server
$ npm install

The Node API is located in the /server folder at the root of our sample application.

Find the config.js.example file and remove the .example extension from the filename. Then open the file:

// server/config.js (formerly config.js.example)
module.exports = {
  AUTH0_AUDIENCE: 'http://localhost:3001/api/'

Change the CLIENT_DOMAIN value to your full Auth0 domain and set the AUTH0_AUDIENCE to your audience (in this example, this is http://localhost:3001/api/). The /api/dragons route will be protected with express-jwt and jwks-rsa.

Note: To learn more about RS256 and JSON Web Key Set, read Navigating RS256 and JWKS.

Our API is now protected, so let's make sure that our Angular application can also interface with Auth0. To do this, we'll activate the src/environments/environment.ts.example file by deleting .example from the file extension. Then open the file and change the [YOUR_CLIENT_ID] and [YOUR_AUTH0_DOMAIN] strings to your Auth0 information:

// src/environments/environment.ts (formerly environment.ts.example)
export const environment = {
  production: false,
  auth: {
    CLIENT_DOMAIN: '[YOUR_AUTH0_DOMAIN]', // e.g., ''

Our app and API are now set up. They can be served by running ng serve from the root folder and node server from the /server folder. The npm start command will run both at the same time for you by using concurrently.

With the Node API and Angular app running, let's take a look at how authentication is implemented.

Authentication Service

Authentication logic on the front end is handled with an AuthService authentication service: src/app/auth/auth.service.ts file. We'll step through this code below.

// src/app/auth/auth.service.ts
import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable, bindNodeCallback, of } from 'rxjs';
import * as auth0 from 'auth0-js';
import { environment } from './../../environments/environment';
import { Router } from '@angular/router';

export class AuthService {
  // Create Auth0 web auth instance
  // @TODO: Update environment variables and remove .example
  // extension in src/environments/environment.ts.example
  private _Auth0 = new auth0.WebAuth({
    clientID: environment.auth.CLIENT_ID,
    domain: environment.auth.CLIENT_DOMAIN,
    responseType: 'id_token token',
    redirectUri: environment.auth.REDIRECT,
    audience: environment.auth.AUDIENCE,
    scope: 'openid profile email'
  // Track whether or not to renew token
  private _authFlag = 'isLoggedIn';
  // Create stream for token
  token$: Observable<string>;
  // Create stream for user profile data
  userProfile$ = new BehaviorSubject<any>(null);
  // Authentication navigation
  onAuthSuccessUrl = '/';
  onAuthFailureUrl = '/';
  logoutUrl = environment.auth.LOGOUT_URL;
  // Create observable of Auth0 parseHash method to gather auth results
  parseHash$ = bindNodeCallback(this._Auth0.parseHash.bind(this._Auth0));
  // Create observable of Auth0 checkSession method to
  // verify authorization server session and renew tokens
  checkSession$ = bindNodeCallback(this._Auth0.checkSession.bind(this._Auth0));

  constructor(private router: Router) { }

  login() {

  handleLoginCallback() {
    if (window.location.hash && !this.authenticated) {
        authResult => {
          window.location.hash = '';
        err => this._handleError(err)

  private _setAuth(authResult) {
    // Observable of token
    this.token$ = of(authResult.accessToken);
    // Emit value for user data subject
    // Set flag in local storage stating this app is logged in
    localStorage.setItem(this._authFlag, JSON.stringify(true));

  get authenticated(): boolean {
    return JSON.parse(localStorage.getItem(this._authFlag));

  renewAuth() {
    if (this.authenticated) {
        authResult => this._setAuth(authResult),
        err => {

  logout() {
    // Set authentication status flag in local storage to false
    localStorage.setItem(this._authFlag, JSON.stringify(false));
    // This does a refresh and redirects back to homepage
    // Make sure you have the logout URL in your Auth0
    // Dashboard Application settings in Allowed Logout URLs
      returnTo: this.logoutUrl,
      clientID: environment.auth.CLIENT_ID

  private _handleError(err) {
    if (err.error_description) {
      console.error(`Error: ${err.error_description}`);
    } else {
      console.error(`Error: ${JSON.stringify(err)}`);


This service uses the auth config variables from environment.ts to instantiate an auth0.js WebAuth instance. Next an _authFlag member is created, which is simply a flag that we can store in local storage. It tells us whether or not to attempt to renew tokens with the Auth0 authorization server (for example, after a full-page refresh or when returning to the app later). All it does is state, "This front-end application thinks this user is authenticated" and then allows us to apply logic based on that estimation and verify whether or not it's accurate.

We'll add and type a token$ observable, which will provide a stream of the access token string. This is for use with the token interceptor. We don't want our interceptor to utilize a stream that emits a default value without any useable values. We'll declare token$ in our _setAuth() method below, when the access token becomes available.

We will use an RxJS BehaviorSubject to provide a stream of the user profile that you can subscribe to anywhere in the app. We'll also store some paths for navigation so the app can easily determine where to send users when authentication succeeds, fails, or the user has logged out.

The next thing that we'll do is create observables of the auth0.js methods parseHash() (which allows us to extract authentication data from the hash upon login) and checkSession() (which allows us to acquire new tokens when a user has an existing session with the authorization server). Using observables with these methods allows us to easily publish authentication events and subscribe to them within our Angular application.

We'll create observables of the callbacks from these two auth0.js methods using using RxJS's bindNodeCallback. In order to preserve the scope of this, we'll bind() it like so:


The login() method authorizes the authentication request with Auth0 using the environment config variables. A login page will be shown to the user and they can then authenticate.

Note: If it's the user's first visit to our app and our callback is on localhost, they'll also be presented with a consent screen where they can grant access to our API. A first party client on a non-localhost domain would be highly trusted, so the consent dialog would not be presented in this case. You can modify this by editing your Auth0 Dashboard API Settings. Look for the "Allow Skipping User Consent" toggle.

We'll receive accessToken, expiresIn, and idTokenPayload in the URL hash from Auth0 when returning to our app after authenticating at the login page. The handleLoginCallback() method subscribes to the parseHash$() observable to stream authentication data (_setAuth()) by creating our token$ observable and emitting a value for the userProfile$ behavior subject. This way, any subscribed components in the app are informed that the token and user data has been updated. The _authFlag is also set to true and stored in local storage so if the user returns to the app later, we can check whether to ask the authorization server for a fresh token. Essentially, the flag serves to tell the authorization server, "This app thinks this user is authenticated. If they are, give me their data." We check the status of the flag in local storage with the accessor method authenticated.

Note: The user profile data takes the shape defined by OpenID standard claims.

The renewAuth() method, if the _authFlag is true, subscribes to the checkSession$() observable to ask the authorization server if the user is indeed authorized (we can pass arguments to this observable as we would to the auth0.js function). If they are, fresh authentication data is returned and we'll run the _setAuth() method to update the necessary authentication streams in our app. If the user is not authorized with Auth0, the _authFlag is removed and the user will be redirected to the URL we set as the authentication failure location.

Next, we have a logout() method that sets the _authFlag to false and logs out of the authentication session on Auth0's server. The Auth0 logout() method then redirects back to the location we set as our logoutUrl.

Once AuthService is provided in app.module.ts, its methods and properties can be used anywhere in our app, such as the home component.

Callback Component

The callback component is where the app is redirected after authentication. This component simply shows a loading message until the login process is completed. It executes the authentication service's handleLoginCallback() method to parse the hash and extract authentication information.

// src/app/callback/callback.component.ts
import { Component, OnInit } from '@angular/core';
import { AuthService } from '../auth/auth.service';

  selector: 'app-callback',
  template: `<div>Loading...</div>`,
  styles: []
export class CallbackComponent implements OnInit {
  constructor(private auth: AuthService) { }

  ngOnInit() {


Making Authenticated API Requests

In order to make authenticated HTTP requests, it's necessary to add an Authorization header with the access token to our outgoing requests. Note that the api.service.ts file does not do this.

Instead, this functionality is in an HTTP interceptor service called token.interceptor.ts.

// src/app/auth/token.interceptor.ts
import { Injectable } from '@angular/core';
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
import { AuthService } from './auth.service';
import { Observable } from 'rxjs';
import { mergeMap } from 'rxjs/operators';

export class InterceptorService implements HttpInterceptor {
  constructor(private auth: AuthService) { }

    req: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> {
    // @NOTE: If you have some endpoints that are public
    // and do not need Authorization header, implement logic
    // here to accommodate that and conditionally let public
    // requests pass through based on your requirements
    return this.auth.token$
        mergeMap(token => {
          if (token) {
            const tokenReq = req.clone({
              setHeaders: { Authorization: `Bearer ${token}` }
            return next.handle(tokenReq);

As mentioned above, we can return the token$ observable to acquire a token, then clone the outgoing HTTP request and attach an Authorization header before sending the request on its way.

The interceptor should be provided like so in the app-routing.module.ts file:

// src/app/app-routing.module.ts
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { InterceptorService } from './auth/token.interceptor';

  imports: [...],
  providers: [
      provide: HTTP_INTERCEPTORS,
      useClass: InterceptorService,
      multi: true
export class AppRoutingModule {}

Note: We set multi to true because we could implement multiple interceptors, which would run in the order of declaration.

Final Touches: Route Guard and Profile Page

A profile page component can show an authenticated user's profile information. However, we only want this component to be accessible if the user is logged in.

With an authenticated API request and login/logout implemented in the Home component, the final touch is to protect our profile route from unauthorized access. The auth.guard.ts route guard can check authentication and activate routes conditionally. The guard is implemented on specific routes of our choosing in the app-routing.module.ts file like so:

// src/app/app-routing.module.ts
import { AuthGuard } from './auth/auth.guard';

  imports: [
        path: 'profile',
        component: ProfileComponent,
        canActivate: [
  providers: [
export class AppRoutingModule {}

To Do: Elegant Error Handling

Now that the primary functionality is there, you'll want to think about gracefully handling and reacting to errors. Some functionality will need to be implemented for this. The errors are there to react to, but you'll want to consider how you prefer to respond to them when they occur.

More Resources

That's it! We have an authenticated Node API and Angular application with login, logout, profile information, and a protected route. To learn more, check out the following resources:


As you saw in this tutorial, the web has capabilities that allow you to build very rich applications. Your real-time chart, for example, adds a huge value to your app because there the user knows that they will have the latest data without having to refresh the page or performing any action. This kind of interactivity improves your users' experiences and will contribute to their happiness.

WDYT? Ready to add some real-time data to the web?