Introduction

We will build a todo list app in this tutorial, using Auth0 for sign in and sign up to our app. In this tutorial, you will learn how to use Passport to integrate with Auth0.

If you want to see where we are headed, here's an example of the final result: https://github.com/passport/todos-express-auth0

Before we dive in, you'll need a working development environment with Node.js and Git, as well as an editor and terminal of your choosing. Take a moment to set up these tools if you have not already done so.

You'll also need an Auth0 account. If you don't already have one, sign up now. This tutorial can be completed using Auth0's free plan.

Let's get started!

We are going to start with a starter app, which has all the scaffolding needed to build a todo list. Let's clone the app:

$ git clone https://github.com/passport/todos-express-starter.git auth0-tutorial

You now have a directory named 'auth0-tutorial'. Let's cd into it:

$ cd auth0-tutorial

Take a moment browse through the files in the starter app. As we work through this tutorial, we'll be using Express as our web framework, along with EJS as our template engine and CSS for styling. We will use SQLite as our database for storing data. Don't worry if you are not familiar with these technologies -- the necessary code will be provided at each step.

Now, let's install the dependencies:

$ npm install

And start the server:

$ npm start

Let's check to see if its working. Open http://localhost:3000 in your browser. You should be greeted with a page explaining how todos help you get things done.

We are going to make the sign in button work. But first, we need to create an app in Auth0.

Create App

Before we can use Auth0 for sign in, we need to create an app in Auth0.

Go to the Auth0 Dashboard.

Navigate to Applications.

If you have an existing application, it will be listed on the applications screen. Click the application to obtain the client ID and secret, and proceed to configure the strategy. Otherwise, continue.

Click Create Application.

Enter a name for the application and choose Regular Web Applications as the application type. Click the Create button.

On the following screen, click the Settings tab. Scroll down and find the Allowed Callback URLs text area. Enter 'http://localhost:3000/oauth2/redirect'. Below that, find the Allowed Logout URLs text area. Enter 'http://localhost:3000/'. Scroll down futher and click Save Changes.

Scroll up to the top and find the Domain, Client ID, and Client Secret values for the newly created app. Next, we will use these values to configure the strategy.

Configure Strategy

Now that we've created an app in Auth0, we can configure Passport to integrate with Auth0.

First, let's create a '.env' file to store the domain, client ID, and client secret we just obtained from Auth0.

$ touch .env

Then, add the domain, client ID and secret. The contents of the file should look something like this:

AUTH0_DOMAIN=__INSERT_DOMAIN_HERE__
AUTH0_CLIENT_ID=__INSERT_CLIENT_ID_HERE__
AUTH0_CLIENT_SECRET=__INSERT_CLIENT_SECRET_HERE__

For this integration, we are going to use Passport and the passport-openidconnect strategy. Install both as dependencies:

$ npm install passport
$ npm install passport-openidconnect

Now, let's create a file that will contain authentication-related functionality:

$ touch routes/auth.js

Add the following code to that file, which configures the strategy to work with Auth0.

var passport = require('passport');
var OpenIDConnectStrategy = require('passport-openidconnect');

passport.use(new OpenIDConnectStrategy({
  issuer: 'https://' + process.env['AUTH0_DOMAIN'] + '/',
  authorizationURL: 'https://' + process.env['AUTH0_DOMAIN'] + '/authorize',
  tokenURL: 'https://' + process.env['AUTH0_DOMAIN'] + '/oauth/token',
  userInfoURL: 'https://' + process.env['AUTH0_DOMAIN'] + '/userinfo',
  clientID: process.env['AUTH0_CLIENT_ID'],
  clientSecret: process.env['AUTH0_CLIENT_SECRET'],
  callbackURL: '/oauth2/redirect',
  scope: [ 'profile' ]
}, function verify(issuer, profile, cb) {
  return cb(null, profile);
}));

Now that the strategy is configured, we are ready to add login routes to the app.

Add Routes

When the user clicks the "Sign in" button, they will be redirected to our app's sign in page, which is hosted by Auth0. Once on that page, the user will log in. After they've logged in, the user will be redirected back to our app.

Open 'routes/auth.js' and add the following code at the end of the file, which creates two routes. The first will redirect the user to the sigin page. The second will process the authentication result when the user is redirected back.

var express = require('express');
var qs = require('querystring');
var router = express.Router();

router.get('/login', passport.authenticate('openidconnect'));

router.get('/oauth2/redirect', passport.authenticate('openidconnect', {
  successRedirect: '/',
  failureRedirect: '/login'
}));

module.exports = router;

Next, we need to add these routes to our app. Open 'app.js' and require the newly created auth routes at line 10, below where 'routes/index' is require'd:

var indexRouter = require('./routes/index');
var authRouter = require('./routes/auth');

Continuing within 'app.js', use the newly require'd authRouter at line 27, below where indexRouter is use'd.

app.use('/', indexRouter);
app.use('/', authRouter);

The routes have been added to the app. Next we need to maintain state when redirecting to Auth0.

Maintain State

When a user signs in to our app via our app's Auth0-hosted sign in page, they are redirected to Auth0. Auth0 takes care of authenticating the user and then redirects them back to our app.

For security, state needs to be maintained between these two redirects. Passport does this automatically, but the app first needs session support. Let's add that now.

Begin by installing the necessary dependencies:

$ npm install express-session
$ npm install connect-sqlite3

Open 'app.js' and require the additional dependencies at line 8, below where 'morgan' is require'd:

var logger = require('morgan');
var session = require('express-session');

var SQLiteStore = require('connect-sqlite3')(session);

Add the following code at line 28, after express.static middleware, to add sessions to the application.

app.use(express.static(path.join(__dirname, 'public')));
app.use(session({
  secret: 'keyboard cat',
  resave: false,
  saveUninitialized: false,
  store: new SQLiteStore({ db: 'sessions.db', dir: './var/db' })
}));

Now that the app can maintain state, the final step is establishing a login session.

Establish Session

Once the user has signed in via Auth0, our app needs a login session to remember who the user is as they navigate the app.

Open 'app.js' and require Passport at line 9, below where 'express-session' is require'd:

var session = require('express-session');
var passport = require('passport');

Add the following code at line 35, after session middleware, to authenticate the session.

app.use(session({
  secret: 'keyboard cat',
  resave: false,
  saveUninitialized: false,
  store: new SQLiteStore({ db: 'sessions.db', dir: './var/db' })
}));
app.use(passport.authenticate('session'));

Finally, we need to configure Passport to manage the login session. Open 'routes/auth.js' and add the following code at line 17:

passport.serializeUser(function(user, cb) {
  process.nextTick(function() {
    cb(null, { id: user.id, username: user.username, name: user.displayName });
  });
});

passport.deserializeUser(function(user, cb) {
  process.nextTick(function() {
    return cb(null, user);
  });
});

Now, let's try signing in.

Start the server:

npm start

Open http://localhost:3000 and click "Sign in."

If this is your first time signing in, go ahead and sign up. Otherwise enter the email address and password for your account.

We are logged in! Go ahead and enter some tasks you've been needing to get done.

At this point, users can sign in and sign up to our app! Next, we will add the ability to sign out.

Log Out

Now that users can sign in and sign up, they'll need a way to sign out.

Open 'routes/auth.js' and add this route at line 40, below the '/oauth2/redirect' route:

router.post('/logout', function(req, res, next) {
  req.logout(function(err) {
    if (err) { return next(err); }
    var params = {
      client_id: process.env['AUTH0_CLIENT_ID'],
      returnTo: 'http://localhost:3000/'
    };
    res.redirect('https://' + process.env['AUTH0_DOMAIN'] + '/v2/logout?' + qs.stringify(params));
  });
});

Return to the app, where you should already be signed in, and click "Sign out."

We've now got a working app where users can sign in, sign up, and sign out!

SEARCH FOR STRATEGIES

0STRATEGIES