Ember

Community maintained

Sample Project

Download a sample project specific to this tutorial configured with your Auth0 API Keys.

This integration guide will walk you through setting up and managing authentication and authorization in your Ember apps using Auth0.

Get Your Application Keys

When you signed up for Auth0, you were invited to create a new client.

There are some details about this client that your application needs to know about to properly communicate with Auth0, including your Client ID and Domain. You can retrieve these values from the settings area for your client in the Auth0 dashboard.

Please note that if you download the samples available for this tutorial, these keys will be pre-populated for you. If you have created more than one client in your account, the sample will come with the values for your Default App.

App Dashboard

Configure Callback URLs

A callback URL is a URL in your application where Auth0 redirects to after the user has authenticated. You need to whitelist a callback URL for your app in the Callback URLs field in your Client Settings. If no callback URLs are set, a mismatch error will be displayed when a user logs in.

If you are following along with the downloadable sample projects for this tutorial directly, the Callback URL should be set to

http://localhost:4200

Install auth0.js

Integrating Auth0 in your application requires the auth0.js library. Install it using npm or yarn.

# installation with npm
npm install --save auth0-js

# installation with yarn
yarn add auth0-js

Once auth0.js is installed, add it to your build system or bring it in to your project with a script tag.

<script type="text/javascript" src="node_modules/auth0-js/build/auth0.js"></script>

If you don't want to use a package manager, auth0.js can also be retrieved from Auth0's CDN.

<script src="https://cdn.auth0.com/js/auth0/8.8/auth0.min.js"></script>

Add Authentication with Auth0

The first step in adding authentication to your Ember application is to provide a way for your users to log in. The fastest, most secure, and most feature-rich way to do this with Auth0 is to use the hosted login page.

When authentication is successful, three items will be returned which can all be used at some point in your application: an access_token, an id_token, and the number of seconds until the access_token expires.

Create an Authentication 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. The name for it is at your discretion, but in these examples it will be called auth and the filename will be auth.js. An instance of the WebAuth object from auth0.js can be created in the service.

Create a service and instantiate auth0.WebAuth. Provide a method called login which calls the authorize method from auth0.js.

// app/services/auth.js

import Ember from 'ember';
import config from 'auth0-ember-samples/config/environment';

const {
  computed,
  Service,
  get
} = Ember;

export default Service.extend({
  auth0: computed(function () {
    return new auth0.WebAuth({
      domain: 'YOUR_AUTH0_DOMAIN',
      clientID: 'YOUR_CLIENT_ID',
      redirectUri: 'http://localhost:4200',
      audience: 'https://YOUR_AUTH0_DOMAIN/userinfo',
      responseType: 'token id_token',
      scope: 'openid'
    });
  }),

  login() {
    get(this, 'auth0').authorize();
  }
});

Checkpoint: Try calling the login method from somewhere in your application. This could be from a button click or in some lifecycle event, just something that will trigger the method so you can see the login page.

hosted login

Finish Out the Authentication Functions

Add some additional methods to the auth service to fully handle authentication in the app.

// app.js

import Ember from 'ember';
import config from 'auth0-ember-samples/config/environment';

const {
  computed,
  Service,
  get,
  RSVP,
  isPresent,
} = Ember;

export default Service.extend({

  // ...
  handleAuthentication() {
    return new RSVP.Promise((resolve, reject) => {
      get(this, 'auth0').parseHash((err, authResult) => {
        if (authResult && authResult.accessToken && authResult.idToken) {
          this.setSession(authResult);
        } else if (err) {
          return reject(err);
        }

        return resolve();
      });
    });
  },

  isAuthenticated: computed(function() {
    return isPresent(this.getSession().access_token) && this.isNotExpired();
  }).volatile(),

  getSession() {
    return {
      access_token: localStorage.getItem('access_token'),
      id_token: localStorage.getItem('id_token'),
      expires_at: localStorage.getItem('expires_at')
    };
  },

  setSession(authResult) {
    if (authResult && authResult.accessToken && authResult.idToken) {
      // Set the time that the access token will expire at
      let expiresAt = JSON.stringify((authResult.expiresIn * 1000) + new Date().getTime());
      localStorage.setItem('access_token', authResult.accessToken);
      localStorage.setItem('id_token', authResult.idToken);
      localStorage.setItem('expires_at', expiresAt);
    }
  },

  logout() {
    // Clear access token and ID token from local storage
    localStorage.removeItem('access_token');
    localStorage.removeItem('id_token');
    localStorage.removeItem('expires_at');
  },

  isNotExpired() {
    // Check whether the current time is past the
    // access token's expiry time
    let expiresAt = this.getSession().expires_at;
    return new Date().getTime() < expiresAt;
  }
});

The file now includes several other methods for handling authentication.

  • 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

About the Authentication Service

The first noteworthy thing happening in this service is that an instance of auth0.WebAuth is created. The options object passed to it includes configuration for your client and domain, a response type to indicate you would like to receive an access_token and id_token after authentication, and an audience and scope which specify that authentication should be OIDC conformant. Also specified is the location that users should be returned to after authentication is complete. In this case, that's a route of /callback, which will be implemented later.

When a user successfully authenticates at Auth0's hosted login page and is redirected back to your application, there will be a hash fragment in the URL containing their authentication information. Contained within will be an access_token, an id_token and an expires_in value. These values are extracted from the URL using the parseHash method from auth0.js and are then saved into local storage with the setSession method. This method also calculates the time at which the access_token will expire using the expires_in value from the hash.

Authentication using JSON Web Tokens is stateless by nature, meaning that there is no information about the user's session stored on your server. In this way, setting up a session for the user on the client side is simply a matter of saving the access_token, id_token, and a time that the access_token expires at in browser storage. Conversely, logging the user out only requires that these items be removed from storage. These examples use local storage to save the tokens and the expiry time, but you may also use session storage or cookies if you wish.

The application needs some way to make decisions about showing or hiding UI elements and restricting routing based on whether or not the user can be considered "authenticated". Once again, since JWT authentication is stateless, there is no real way to say whether the user is authenticated in any traditional sense, but there are clues that can be used. The best clue to go with is whether or not the access_token is expired. If it is expired, anything meaningful that the user could do with it--such as a call to your API for protected resources--will not work. It's at this point that the user would need to reauthenticate and get a new token. The isAuthenticated method checks whether the expiry time for the access_token has passed or not so that the above-mentioned decisions can be made.

Provide a Login Control

Provide a template with controls for the user to log in and log out.

<!-- app/templates/index.hbs -->

<div>
  <a href="#" class="login" {{action "login"}}>Log In</a>
</div>

The action added to the Log In control makes the appropriate call to the login method in auth.js to allow the user to log in. When the Log In control is clicked, the user will be redirected to Auth0's hosted login page.

The hosted login page uses the Lock widget and is configured in the Hosted Pages section in your Auth0 dashboard. To customize the look and feel of the Lock widget, see the configuration options documentation.

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 function in auth.js is responsbile for processing the hash.

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

// app/routes/application.js

import Ember from 'ember';

const {
  Route,
  inject: {
    service,
  },
  get,
} = Ember;

export default Route.extend({
  auth: service(),
  beforeModel() {
    if (get(this, 'auth.isAuthenticated')) {
      return;
    }

    return get(this, 'auth')
      .handleAuthentication()
      .then(() => {
        if (get(this, 'auth.isAuthenticated')) {
          this.transitionTo('protected')
        }
      });
  },
});

Create a Protected Route

After a user authenticates and returns to your application, you may wish to send them to a protected route. The transition logic is demonstrated above in the transitionTo call after authentication. Add a new route called protected and check whether the user is authenticated before allowing them to see it.

// app/routes/protected.js

import Ember from 'ember';

const {
  Route,
  inject: {
    service,
  },
  get,
} = Ember;

export default Route.extend({
  auth: service(),
  beforeModel() {
    if (!get(this, 'auth.isAuthenticated')) {
      return this.replaceWith('application');
    }
  }
});

Add a template for this route.

<!-- app/templates/protected.hbs -->

<a href="#" {{action "logout"}}>
    Log Out
</a>
<br/>
<h2>You are logged in!</h2>

Notice that there is also a Log Out control in this route which has an action of logout. This will call the logout method on the auth service allowing the user to log out.

Embedded Login

Auth0's hosted login page provides the fastest, most secure, and most feature-rich way to implement authentication in your app. If required, the Lock widget can also be embedded directly into your application, but certain features such as single sign-on won't be accessible. It is highly recommended that you use the hosted login page (as covered in this tutorial), but if you wish to embed the Lock widget directly in your application, follow the Embedded Login sample.

Use Auth0 for FREECreate free Account