SPA + API: Angular 2 Implementation for the SPA

This document is part of the SPA + API Architecture Scenario and it explains how to implement the SPA in Angular 2. Please refer to the scenario for information on the implemented solution.

The full source code for the Angular 2 implementation of the SPA can be found in this GitHub repository.

1. Configuration

Your application will require certain configuration information. Before carrying on with the rest of the implementation, create an AuthConfig interface which will contain various configuration values. Place this interface in a file called auth0-variables.ts.

interface AuthConfig {
  clientID: string;
  domain: string;
  callbackURL: string;
  apiUrl: string;
export const AUTH_CONFIG: AuthConfig = {
  clientID: '',
  domain: '',
  callbackURL: 'http://localhost:4200/callback',
  apiUrl: ''

2. Authorize the User

Create an Authorization Service

The best way to manage and coordinate the tasks necessary for user authentication is to create a reusable service. With the service in place, you'll be able to call its methods throughout your application. An instance of the WebAuth object from auth0.js can be created in the service.

import { Injectable } from '@angular/core';
import { AUTH_CONFIG } from './auth0-variables';
import { Router } from '@angular/router';
import 'rxjs/add/operator/filter';
import auth0 from 'auth0-js';

export class AuthService {

  userProfile: any;
  requestedScopes: string = 'openid profile read:timesheets create:timesheets';

  auth0 = new auth0.WebAuth({
    clientID: AUTH_CONFIG.clientID,
    domain: AUTH_CONFIG.domain,
    responseType: 'token id_token',
    audience: AUTH_CONFIG.apiUrl,
    redirectUri: AUTH_CONFIG.callbackURL,
    scope: this.requestedScopes

  constructor(public router: Router) {}

  public login(): void {

  public handleAuthentication(): void {
    this.auth0.parseHash((err, authResult) => {
      if (authResult && authResult.accessToken && authResult.idToken) {
        window.location.hash = '';
      } else if (err) {
        alert('Error: ${err.error}. Check the console for further details.');

  private setSession(authResult): void {
    // Set the time that the access token will expire at
    const expiresAt = JSON.stringify((authResult.expiresIn * 1000) + new Date().getTime());

    // If there is a value on the scope param from the authResult,
    // use it to set scopes in the session for the user. Otherwise
    // use the scopes as requested. If no scopes were requested,
    // set it to nothing
    const scopes = authResult.scope || this.requestedScopes || '';

    localStorage.setItem('access_token', authResult.accessToken);
    localStorage.setItem('id_token', authResult.idToken);
    localStorage.setItem('expires_at', expiresAt);
    localStorage.setItem('scopes', JSON.stringify(scopes));

  public logout(): void {
    // Remove tokens and expiry time from localStorage
    // Go back to the home route

  public isAuthenticated(): boolean {
    // Check whether the current time is past the
    // access token's expiry time
    const expiresAt = JSON.parse(localStorage.getItem('expires_at'));
    return new Date().getTime() < expiresAt;

  public userHasScopes(scopes: Array<string>): boolean {
    const grantedScopes = JSON.parse(localStorage.getItem('scopes')).split(' ');
    return scopes.every(scope => grantedScopes.includes(scope));

The service includes several methods for handling authentication.

  • login: calls authorize from auth0.js which redirects users to the hosted login page
  • handleAuthentication: looks for an authentication result in the URL hash and processes it with the parseHash method from auth0.js
  • setSession: sets the user's access_token, id_token, and a time at which the access_token will expire
  • logout: removes the user's tokens from browser storage
  • isAuthenticated: checks whether the expiry time for the access_token has passed

Process the Authentication Result

When a user authenticates at Auth0's hosted login page and is then redirected back to your application, their authentication information will be contained in a URL hash fragment. The handleAuthentication method in the AuthService is responsibile for processing the hash.

Call handleAuthentication in your app's root component so that the authentication hash fragment can be processed when the app first loads after the user is redirected back to it.

// src/app/app.component.ts

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

  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']

export class AppComponent {

  constructor(public auth: AuthService) {

Add the Callback Component

Using Auth0's hosted login page means that users are taken away from your application to a page hosted by Auth0. After they successfully authenticate, they are returned to your application where a client-side session is set for them.

You can choose to have users return to any URL in your application that you like; however, it is recommended that you create a dedicated callback route to serve as a central location that the user will be returned to upon successful authentication. Having a single callback route is beneficial for two main reasons:

  • It prevents the need to whitelist multiple (and sometimes unknown) callback URLs
  • It serves as a place to show a loading indicator while your application sets the user's client-side session

Create a component named CallbackComponent and populate it with a loading indicator.

<!-- app/callback/callback.html -->

<div class="loading">
  <img src="assets/loading.svg" alt="loading">

This example assumes some kind of loading spinner is available in an assets directory. See the downloadable sample for a demonstration.

After authentication, users will be taken to the /callback route for a brief time where they will be shown a loading indicator. During this time, their client-side session will be set, after which they will be redirected to the /home route.

3. Get the User Profile

Extract info from the token

This section shows how to retrieve the user info using the access_token and the /userinfo endpoint. Alternatively, you can just decode the id_token using a library (make sure you validate it first). The output will be the same. If you need additional user information consider using the our Management API.

To obtain the user's profile, update the existing AuthService class. Add a getProfile function which will extract the user's access_token from local storage, and then pass that call the userInfo function to retrieve the user's information.

// Existing code from the AuthService class is omitted in this code sample for brevity
export class AuthService {
  public getProfile(cb): void {
    const accessToken = localStorage.getItem('access_token');
    if (!accessToken) {
      throw new Error('Access token must exist to fetch profile');

    const self = this;
    this.auth0.client.userInfo(accessToken, (err, profile) => {
      if (profile) {
        self.userProfile = profile;
      cb(err, profile);

You can now simply call this function from any service where you want to retrieve and display information about the user.

For example you may choose to create a new component to display the user's profile information:

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

  selector: 'app-profile',
  templateUrl: './profile.component.html',
  styleUrls: ['./profile.component.css']
export class ProfileComponent implements OnInit {

  profile: any;

  constructor(public auth: AuthService) { }

  ngOnInit() {
    if (this.auth.userProfile) {
      this.profile = this.auth.userProfile;
    } else {
      this.auth.getProfile((err, profile) => {
        this.profile = profile;

The template for this component looks as follows:

<div class="panel panel-default profile-area">
  <div class="panel-heading">
  <div class="panel-body">
    <img src="{{profile?.picture}}" class="avatar" alt="avatar">
      <label><i class="glyphicon glyphicon-user"></i> Nickname</label>
      <h3 class="nickname">{{ profile?.nickname }}</h3>
    <pre class="full-profile">{{ profile | json }}</pre>

4. Call the API

The angular2-jwt module can be used to automatically attach JSON Web Tokens to requests made to your API. It does this by providing an AuthHttp class which is a wrapper over Angular's Http class.

Install angular2-jwt:

# installation with npm
npm install --save angular2-jwt

# installation with yarn
yarn add angular2-jwt

Create a factory function with some configuration values for angular2-jwt and add it to the providers array in your application's @NgModule. The factory function should have a tokenGetter functon which fetches the access_token from local storage.

import { Http, RequestOptions } from '@angular/http';
import { AuthHttp, AuthConfig } from 'angular2-jwt';

export function authHttpServiceFactory(http: Http, options: RequestOptions) {
  return new AuthHttp(new AuthConfig({
    tokenGetter: (() => localStorage.getItem('access_token'))
  }), http, options);

  declarations: [...],
  imports: [...],
  providers: [
      provide: AuthHttp,
      useFactory: authHttpServiceFactory,
      deps: [Http, RequestOptions]
  bootstrap: [...]

After angular2-jwt is configured, you can use the AuthHttp class to make secure calls to your API from anywhere in the application. To do so, inject AuthHttp in any component or service where it is needed and use it just as you would use Angular's regular Http class.

import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import { AuthHttp } from 'angular2-jwt';
import 'rxjs/add/operator/map';
import { NewTimesheetModel } from '../models/new-timesheet-model';

export class TimesheetsService {

  constructor(public authHttp: AuthHttp) { }

  addTimesheet(model: NewTimesheetModel) {
    return'http://localhost:8080/timesheets', JSON.stringify(model));

  getAllTimesheets() {
    return this.authHttp.get('http://localhost:8080/timesheets')
      .map(res => res.json())

5. Renew the Access Token

Renewing the user's access_token requires that a static HTML file to be served. The server setup you choose to do this is at your discretion, but an example using Node.js and express is given here.

Create a simple server with express:

const express = require('express');
const app = express();
const cors = require('cors');
const staticFile = require('connect-static-file');

app.use('/silent', staticFile('${__dirname}/silent.html'));

console.log('Listening on http://localhost:3001');

And add a file called silent.html:

<!doctype html>
  <meta charset="utf-8">
  <script src=""></script>

    if (!AUTH0_CLIENT_ID || !AUTH0_DOMAIN) {
      alert('Make sure to set the AUTH0_CLIENT_ID and AUTH0_DOMAIN variables in silent.html.');

    var webAuth = new auth0.WebAuth({
      domain: AUTH0_DOMAIN,
      clientID: AUTH0_CLIENT_ID,
      scope: 'openid profile',
      responseType: 'token id_token',
      redirectUri: 'http://localhost:4200'
    webAuth.parseHash(window.location.hash, function (err, response) {
      parent.postMessage(err || response, 'http://localhost:4200');

In this example, the server is running at localhost:3001.The silent.html file makes reference to localhost:4200 which is the address for the Angular SPA.

Next we’ll need to update the Angular SPA. Add a method to the AuthService which calls the renewAuth method from auth0.js. If the renewal is successful, use the existing setSession method to set the new tokens in local storage.

public renewToken() {
    audience: AUTH_CONFIG.apiUrl,
    redirectUri: AUTH_CONFIG.silentCallbackURL,
    usePostMessage: true
  }, (err, result) => {
    if (!err) {

This will load the silent callback page added earlier in an invisible iframe, make a call to Auth0, and give back the result.

In the AuthService class, add a method called scheduleRenewal to set up a time at which authentication should be silently renewed. In the sample below this is set up to happen 30 seconds before the actual token expires. Also add a method called unscheduleRenewal which will unsubscribe from the Observable.

public scheduleRenewal() {
  if (!this.isAuthenticated()) return;

  const expiresAt = JSON.parse(window.localStorage.getItem('expires_at'));

  const source = Observable.of(expiresAt).flatMap(
    expiresAt => {

      const now =;

      // Use the delay in a timer to
      // run the refresh at the proper time
      var refreshAt = expiresAt - (1000 * 30); // Refresh 30 seconds before expiry
      return Observable.timer(Math.max(1, refreshAt - now));

  // Once the delay time from above is
  // reached, get a new JWT and schedule
  // additional refreshes
  this.refreshSubscription = source.subscribe(() => {

public unscheduleRenewal() {
  if (!this.refreshSubscription) return;

Finally you need to initiate the schedule renewal. This can be done by calling the cheduleRenewal inside your AppComponent which will happen when the page is loaded. This will occur after every authentication flow, either when the user explicitly logs in, or when the silent authentication happens.g