In this project, we'll use passport
to handle authenticating users. Passport can use many different strategies
to authenticate users. However, we'll take a look at just one of them for this project. We are going to use the auth0
strategy. We'll have to sign-up at manage.auth0.com
to get an app (aka client) that we can log in to.
Fork
andclone
this repository.cd
into the project directory.- Run
npm install
.
In this step, we'll install the required dependencies to use passport and the auth0
strategy in a node application.
- Run
npm install --save passport passport-auth0
.
In this step, we'll go to manage.auth0.com
to create an account and modify the default application they give us.
- Go to
manage.auth0.com
. - Register for an account.
- Set the account type to
Personal
. - Set the role to
Developer
. - Set the project to
Just playing around
.
- Set the account type to
- Log in to your Auth0 account.
- Go to
Applications
using the left navigation bar. - Click on
Settings
for the Default App.- Change the
Application Type
toMachine To Machine
. - Change the
Token Endpoint Authentication Method
toBasic
. - Change the
Allowed Callback URLs
tohttp://localhost:3000/login
. - Change the
Allowed Origins
tohttp://localhost:3000
- Click
Show Advanced Settings
. - Click
OAuth
underAdvanced Settings
. - Toggle off the
OIDC Conformant
toggle. - Scroll back up and toggle off the
Use Auth0 instead of the IdP to do Single Sign On
toggle.
- Change the
- Click
Save Changes
. - Keep the page open, we'll need the
domain
,id
, andsecret
later.
In this step, we'll create a .env
file and strategy.js
. We'll install and configure the dotenv
package and add .env
to our .gitignore
so we can keep the client domain
, id
, and secret
off of GitHub. We'll then require it in strategy.js
and configure strategy.js
to use the auth0
strategy.
- Install
dotenv
by runningnpm install --save dotenv
. - Create a
.env
file. - Open
.env
.- The file should have
DOMAIN
,CLIENT_ID
, andCLIENT_SECRET
properties. - The values should equal the values of your
domain
,clientID
, andclientSecret
frommanage.auth0.com
.
- The file should have
- Add
.env
to.gitignore
. - Open
index.js
. - Require and configure
dotenv
at the top of the file. - Create a
strategy.js
file. - Open
strategy.js
. - Require the
passport-auth0
strategy in a variable calledAuth0Strategy
. - Use
module.exports
to export anew Auth0Strategy
.-
Syntax
module.exports = new Auth0Strategy({ domain: '...', clientID: '...', clientSecret: '...', callbackURL: '/login', scope: 'openid email profile' }, function(accessToken, refreshToken, extraParams, profile, done) { // accessToken is the token to call Auth0 API (not needed in the most cases) // extraParams.id_token has the JSON Web Token // profile has all the information from the user return done(null, profile); } );
-
- Modify the
domain
,clientID
, andclientSecret
to use the values from.env
.
strategy.js
const Auth0Strategy = require('passport-auth0');
const { DOMAIN, CLIENT_ID, CLIENT_SECRET } = process.env;
module.exports = new Auth0Strategy({
domain: DOMAIN,
clientID: CLIENT_ID,
clientSecret: CLIENT_SECRET,
callbackURL: '/login',
scope: 'openid email profile'
},
function(accessToken, refreshToken, extraParams, profile, done) {
// accessToken is the token to call Auth0 API (not needed in the most cases)
// extraParams.id_token has the JSON Web Token
// profile has all the information from the user
return done(null, profile);
}
);
In this step, we'll configure our app to use sessions and passport with our newly created strategy.
- Open
index.js
. - Require
passport
andstrategy
fromstrategy.js
. - Configure the app to use sessions.
- Initialize passport and configure passport to use sessions.
- Configure passport to use our required strategy.
index.js
require('dotenv').config();
const express = require('express');
const session = require('express-session');
const passport = require('passport');
const strategy = require(`${__dirname}/strategy.js`);
const app = express();
app.use( session({
secret: 'sup dude',
resave: false,
saveUninitialized: false
}));
app.use( passport.initialize() );
app.use( passport.session() );
passport.use( strategy );
const port = 3000;
app.listen( port, () => { console.log(`Server listening on port ${port}.`); } );
In this step, we'll use the serializeUser
and deserializeUser
methods of passport. These methods get called before a successful redirect. We can use these methods to pick what properties we want to store on session.
- Open
index.js
. - Call the
passport.serializeUser
method and pass in a function as the first argument.- This function should have a
user
anddone
parameter. - This function should call
done
withnull
as the first argument and an object as the second argument.- Use an object that only has the
id
,displayName
,nickname
, andemail
fromuser
.
- Use an object that only has the
- This function should have a
- Call the
passport.deserializeUser
method and pass in a function as the first argument.- This function should should have a
obj
anddone
parameter.obj
will equal the object we passed intodone
fromserializeUser
.
- This function should call
done
withnull
as the first argument andobj
as the second argument.- After
done
is finished, the value ofobj
is then stored onreq.user
andreq.session.passport.user
.
- After
- This function should should have a
index.js
require('dotenv').config();
const express = require('express');
const session = require('express-session');
const passport = require('passport');
const strategy = require(`${__dirname}/strategy.js`);
const app = express();
app.use( session({
secret: 'sup dude',
resave: false,
saveUninitialized: false
}));
app.use( passport.initialize() );
app.use( passport.session() );
passport.use( strategy );
passport.serializeUser(function(user, done) {
done(null, { id: user.id, display: user.displayName, nickname: user.nickname, email: user.emails[0].value });
});
passport.deserializeUser(function(obj, done) {
done(null, obj);
});
const port = 3000;
app.listen( port, () => { console.log(`Server listening on port ${port}.`); } );
In this step, we'll create a login endpoint that will call the authenticate
method on passport. We'll then configure it to redirect
to a /me
endpoint on success and the /login
endpoint on failure. We'll also enable failureFlash
so passport can flash an error message on failure.
- Open
index.js
. - Create a
GET
endpoint at/login
that calls theauthenticate
method on passport.- The first argument should be a string of the strategy:
'auth0'
. - The second argument should be a configuration object:
- Add a
successRedirect
property that equals'/me'
. - Add a
failureRedirect
property that equals'/login'
. - Add a
failureFlash
property that equalstrue
.
- Add a
- The first argument should be a string of the strategy:
index.js
require('dotenv').config();
const express = require('express');
const session = require('express-session');
const passport = require('passport');
const strategy = require(`${__dirname}/strategy.js`);
const app = express();
app.use( session({
secret: 'sup dude',
resave: false,
saveUninitialized: false
}));
app.use( passport.initialize() );
app.use( passport.session() );
passport.use( strategy );
passport.serializeUser(function(user, done) {
done(null, { id: user.id, display: user.displayName, nickname: user.nickname, email: user.emails[0].value });
});
passport.deserializeUser(function(obj, done) {
done(null, obj);
});
app.get( '/login',
passport.authenticate('auth0',
{ successRedirect: '/me', failureRedirect: '/login', failureFlash: true }
)
);
const port = 3000;
app.listen( port, () => { console.log(`Server listening on port ${port}.`); } );
In this step, we'll create a /me
endpoint that checks to see if req.user
exists. If it does, it will send our user object. If it doesn't, it will redirect to the /login
endpoint.
- Create a
GET
endpoint at/me
that checks to see ifreq.user
exists.- If it does, return a status 200 with the
req.user
object. - If it doesn't, redirect to
/login
.
- If it does, return a status 200 with the
index.js
require('dotenv').config();
const express = require('express');
const session = require('express-session');
const passport = require('passport');
const strategy = require(`${__dirname}/strategy.js`);
const app = express();
app.use( session({
secret: 'sup dude',
resave: false,
saveUninitialized: false
}));
app.use( passport.initialize() );
app.use( passport.session() );
passport.use( strategy );
passport.serializeUser(function(user, done) {
done(null, { id: user.id, display: user.displayName, nickname: user.nickname, email: user.emails[0].value });
});
passport.deserializeUser(function(obj, done) {
done(null, obj);
});
app.get( '/login',
passport.authenticate('auth0',
{ successRedirect: '/me', failureRedirect: '/login', failureFlash: true }
)
);
app.get('/me', ( req, res, next) => {
if ( !req.user ) {
res.redirect('/login');
} else {
// req.user === req.session.passport.user
// console.log( req.user )
// console.log( req.session.passport.user );
res.status(200).send( JSON.stringify( req.user, null, 10 ) );
}
});
const port = 3000;
app.listen( port, () => { console.log(`Server listening on port ${port}.`); } );
In this step, we'll open a browser and see if we can log in to our Auth0 client.
- Start your server
- Open a browser and navigate to
http://localhost:3000/login
. - Sign up for the client and then log in to it.
If you see a problem or a typo, please fork, make the necessary changes, and create a pull request so we can review your changes and merge them into the master repo and branch.
© DevMountain LLC, 2017. Unauthorized use and/or duplication of this material without express and written permission from DevMountain, LLC is strictly prohibited. Excerpts and links may be used, provided that full and clear credit is given to DevMountain with appropriate and specific direction to the original content.