Integrate SimpleLogin using passportjs

This is an example on how to integrate SimpleLogin with passportjs, a popular authentication middleware for NodeJS. The code can be found on https://github.com/simple-login/simplelogin-examples/tree/master/passport-oauth2-example

This example is inspired from a similar guide from Okta.

Make sure to create an app, copy the client-id and client-secret (cf App Credential) and export these values into env variables. and run the code:

export CLIENT_ID={your_client_id}
export CLIENT_SECRET={your_client_secret}

You can then run the code and enjoy the demo at http://localhost:3000.

npm install
npm run

Below is the detailed steps that can be useful when adding SimpleLogin into a existing project. As SimpleLogin follows OAuth2 protocol, this guide can also be used as a introduction on how to use passportjs with OAuth2 .

Step 1: bootstrap

Install express-generator to generate the project:

npm install express-generator -g

Init the project using express-generator:

express -e --git passport-oauth2-example

Let's make sure that the bootstrap code is running correctly:

npm install && npm start

Now localhost:3000 should show this quite empty page

Step 1

Step 2: Install passportjs and integrate SimpleLogin

To store user information in the session, passportjs uses express-session. After obtaining the access_token, we also need to call /userinfo endpoint so let's add axios as well:

npm install express-session@1.16.2 \
passport@0.4.0 \
passport-oauth@1.0.0 \
axios@0.19.0 \
--save

Setup express-session by adding the following lines into app.js, just above the var app = express(); line.

app.use(session({
secret: 'my-precious',
resave: false,
saveUninitialized: true
}));

Add the following lines just below the app.use(express.static(path.join(__dirname, 'public'))); to tell express to use passportjs for sessions:

app.use(passport.initialize());
app.use(passport.session());

We also need tell passportjs how to serialize/deserialize user to/from session:

passport.serializeUser((user, next) => {
next(null, user);
});
passport.deserializeUser((obj, next) => {
next(null, obj);
});

Phew, all setup with passportjs finally done! Finally it's time to integrate SimpleLogin!

Config passportjs to use SimpleLogin authorization and token URL and obtain user information once we have the accessToken:

passport.use('oauth2', new OAuth2Strategy({
authorizationURL: 'https://app.simplelogin.io/oauth2/authorize',
tokenURL: 'https://app.simplelogin.io/oauth2/token',
clientID: process.env.CLIENT_ID,
clientSecret: process.env.CLIENT_SECRET,
callbackURL: 'http://localhost:3000/authorization-code/callback'
},
function (accessToken, refreshToken, profile, done) {
// with accessToken, we can obtain user information
// by calling the `userinfo` endpoint
axios({
method: 'get',
url: 'https://app.simplelogin.io/oauth2/userinfo',
headers: {
Authorization: accessToken
}
}).then(res => {
console.log(res);
var user = { email: res.data.email, name: res.data.name };
done(null, user);
}).catch(err => {
console.log("error:", err);
})
}
));

When user logs in at /login, let's call passportjs:

// call passport when user logs in
app.use('/login', passport.authenticate('oauth2'));

We also need to setup the callback route that is called when user authorizes this application on SimpleLogin. This is the second step in OAuth2 Authorization Code Grant Type flow.

// Once user authorizes this client, the browser will redirect him/her back to this route. This route the `callbackURL` when we setup passport
app.use('/authorization-code/callback',
passport.authenticate('oauth2', {
successRedirect: '/profile',
failureRedirect: '/login',
failureFlash: true
})
);

Step 3: A simple login/logout

Let's create a quick profile page to display user data that we obtain from SimpleLogin. First create a profile.ejs file inside views/:

<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
<link rel='stylesheet' href='/stylesheets/style.css' />
</head>
<body>
<h1><%= title %></h1>
<p>Welcome <%= user.name %>!</p>
<div>User data: <%= JSON.stringify(user) %></div>
<a href="/logout">Logout</a>
</body>
</html>

Also add the login button to the home page by adding this line into index.ejs file:

<a href="/login">Connect with SimpleLogin</a>

Then create routes for this page and the /logout route:

// Redirect user to /login if user accidentally goes to /profile route
function ensureLoggedIn(req, res, next) {
if (req.isAuthenticated()) {
return next();
}
res.redirect('/login')
}
app.use('/profile', ensureLoggedIn, (req, res) => {
res.render('profile', { title: 'Express', user: req.user });
});
// logout consists of simply emptying the session
app.get('/logout', (req, res) => {
req.logout();
req.session.destroy();
res.redirect('/');
});

Profit!

Now if you run the server again with npm start and go to http://localhost:3000, you should see this screen:

Clicking on Connect with SimpleLogin button will bring you to the authorization page on SimpleLogin:

Clicking on Allow bring user back to the local website and display user information obtained from SimpleLogin:

Congratulations, you just integrated SimpleLogin!