Ionic 2+

Sample Project

Download this sample project configured with your Auth0 API Keys.

System Requirements
  • Ionic 3.x
  • Angular 4+
Show requirements

Overview

To integrate Auth0 in a hybrid Ionic app, you can use the @auth0/cordova package available on npm. This package provides an interface with cordova which allows you to use the Proof Key for Code Exchange spec. PKCE is recommended for native and hybrid applications to mitigate the threat of authorization code interception.

Set Up Your Package Identifier

To set up or get your package identifier (used several times throughout this tutorial), you should take a look at your config.xml and get it from this line:

<widget id="YOUR_PACKAGE_ID" version="0.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">

Set Up the Client

Go to the Application Settings section in the Auth0 dashboard and make sure that the Allowed Callback URLs contains the following value (replace `YOUR_PACKAGE_ID` with your app identifier):

YOUR_PACKAGE_ID://YOUR_AUTH0_DOMAIN/cordova/YOUR_PACKAGE_ID/callback

Make sure that Allowed Origin (CORS) has the following value:

file://*

Lastly, make sure that Client Type is set to Native

Install Dependencies

You'll need these libraries:

npm install auth0-js @auth0/cordova --save

After @auth0-cordova is installed, it needs to be configured by modifying your app.component.ts to set up URL redirects:

// app.component.ts

import { Component } from '@angular/core';
import { Platform } from 'ionic-angular';
import { StatusBar } from '@ionic-native/status-bar';
import { SplashScreen } from '@ionic-native/splash-screen';

import { HomePage } from '../pages/home/home';

// Import Auth0Cordova
import Auth0Cordova from '@auth0/cordova';

@Component({
  templateUrl: 'app.html'
})
export class MyApp {
  rootPage:any = HomePage;

  constructor(platform: Platform, statusBar: StatusBar, splashScreen: SplashScreen) {
    platform.ready().then(() => {
      statusBar.styleDefault();
      splashScreen.hide();

      // Add this function
      (<any>window).handleOpenURL = (url) => {
        Auth0Cordova.onRedirectUri(url);
      };

    });
  }
}

Add Cordova Plugins

You must install the SafariViewController plugin from Cordova to be able to show the Login popup. The seed project already has this plugin added, but if you are adding Auth0 to your own application you need to run the following command:

ionic cordova plugin add cordova-plugin-safariviewcontroller

You'll also need to install the CustomURLScheme from Cordova to handle redirects properly. The seed project has it already, but if you're adding Auth0 to your own project, you'll need to run this command (replace YOUR_PACKAGE_ID with your app identifier):

ionic cordova plugin add cordova-plugin-customurlscheme --variable URL_SCHEME={YOUR_PACKAGE_ID} --variable ANDROID_SCHEME={YOUR_PACKAGE_ID} --variable ANDROID_HOST=YOUR_AUTH0_DOMAIN --variable ANDROID_PATHPREFIX=/cordova/{YOUR_PACKAGE_ID}/callback

Create an Authentication Service and Configure Auth0

To coordinate authentication tasks, it's best to set up an injectable service that can be reused across the application. This service needs methods for logging users in and out, as well as checking their authentication state. Be sure to replace YOUR_PACKAGE_ID with your apps identifier in the configuration block.

// src/services/auth.service.ts

import { Injectable, NgZone } from '@angular/core';
import { Observable, Subscription } from 'rxjs';

import Auth0Cordova from '@auth0/cordova';
import Auth0 from 'auth0-js';

const auth0Config = {
  // needed for auth0
  clientID: 'YOUR_CLIENT_ID',

  // needed for auth0cordova
  clientId: 'YOUR_CLIENT_ID',
  domain: 'YOUR_AUTH0_DOMAIN',
  callbackURL: location.href,
  packageIdentifier: 'YOUR_PACKAGE_ID'
};


@Injectable()
export class AuthService {
  auth0 = new Auth0.WebAuth(auth0Config);
  accessToken: string;
  idToken: string;
  user: any;

  constructor(public zone: NgZone) {
    this.user = this.getStorageVariable('profile');
    this.idToken = this.getStorageVariable('id_token');
  }

  private getStorageVariable(name) {
    return JSON.parse(window.localStorage.getItem(name));
  }

  private setStorageVariable(name, data) {
    window.localStorage.setItem(name, JSON.stringify(data));
  }

  private setIdToken(token) {
    this.idToken = token;
    this.setStorageVariable('id_token', token);
  }

  private setAccessToken(token) {
    this.accessToken = token;
    this.setStorageVariable('access_token', token);
  }

  public isAuthenticated() {
    const expiresAt = JSON.parse(localStorage.getItem('expires_at'));
    return Date.now() < expiresAt;
  }

  public login() {
    const client = new Auth0Cordova(auth0Config);

    const options = {
      scope: 'openid profile offline_access'
    };

    client.authorize(options, (err, authResult) => {
      if(err) {
        throw err;
      }

      this.setIdToken(authResult.idToken);
      this.setAccessToken(authResult.accessToken);

      const expiresAt = JSON.stringify((authResult.expiresIn * 1000) + new Date().getTime());
      this.setStorageVariable('expires_at', expiresAt);

      this.auth0.client.userInfo(this.accessToken, (err, profile) => {
        if(err) {
          throw err;
        }

        profile.user_metadata = profile.user_metadata || {};
        this.setStorageVariable('profile', profile);
        this.zone.run(() => {
          this.user = profile;
        });
      });
    });
  }

  public logout() {
    window.localStorage.removeItem('profile');
    window.localStorage.removeItem('access_token');
    window.localStorage.removeItem('id_token');
    window.localStorage.removeItem('expires_at');

    this.idToken = null;
    this.accessToken = null;
    this.user = null;
  }

}

The service can now be injected wherever it is needed.

View Auth0 Data After Logging In

You will likely want some kind of profile area for users to see their information. Depending on your needs, this can also serve as the place for them to log in and out.

For a demo in your component, simply inject the AuthService.

// src/pages/home/home.ts

import { Component } from '@angular/core';

import { AuthService } from '../../services/auth.service';

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {

  constructor(public auth: AuthService) {}

}

The AuthService is now accessible in the view and can be used to conditionally hide and show elements depending on whether the user has a valid JWT in local storage.

<!-- src/pages/home/home.html -->

<ion-header>
  <ion-navbar>
    <ion-title>
      Home Page
    </ion-title>
  </ion-navbar>
</ion-header>

<ion-content padding>

  <!-- just a login button if not authenticated -->
  <div *ngIf="!auth.isAuthenticated()">
    <button ion-button block color="primary" (click)="auth.login()">Login</button>
  </div>

  <!-- a card with your picture and name, plus a logout button -->
  <div *ngIf="auth.isAuthenticated()">
    <ion-card>
      <img [src]="auth.user.picture" />
      <ion-card-content>
        <ion-card-title>{{ auth.user.name }}</ion-card-title>
      </ion-card-content>
    </ion-card>
    <button ion-button block color="primary" (click)="auth.logout()">Logout</button>
  </div>

</ion-content>

auth0 lock

Troubleshooting

Cannot read property 'isAvailable' of undefined

This means that you're attempting to test this in a browser. At this time you'll need to run this either in an emulator or on a device.

Completely blank page when launching the app

This could either mean that you've built the seed project using Ionic 1, or that the device where you are testing it isn't entirely supported by Ionic 2 yet. Be sure to check the console for errors.

Use Auth0 for FREECreate free Account