This is another tutorial from the series about hapi. Today many applications have the need to provide social login functionality for the most important providers (Google, Facebook, Twitter, Github...). With hapi this is really easy to accomplish.
Our Application
We are going to build a very simple application, that implements a social login functionality using Twitter as an example.
It should give you an idea of just how simple this is using a hapi plugin called bell.
Getting started
Make sure you have one of the latest versions of Node installed on your machine (currently v6.2.1) as we use some of the new ES6 features.
Everything setup? Let's continue...
Start fast
If you want to skip the step by step copy and paste, just clone the Github Repository and follow the explanations. Otherwise just skip this section.
git clone https://github.com/p-meier/hapi-social-login.git
cd hapi-social-login
npm install
Step 1: Create a Twitter application
Before we can actually start to code we have to create a Twitter application that will be granted by the user.
To do this goto apps.twitter.com, sign in and click on Create New App. Now fill out the form like this:
You can use all values as seen in the screenshot except the name of the application - is has to be unique and you have to think of your own. Scroll down, accept the Developer Agreement and click on Create your Twitter application.
You should see something similar to this. Switch to the tab called Keys and Access Tokens. There you find the Consumer Key and Consumer Secret which we will need later on...
Congratulations! You have successfully created your Twitter application for this tutorial. Now we can move on to the coding part.
Step 2: Create the application
This is the file structure of our application.
- node_modules/ // created by 'npm install'
- package.json // dependencies and project info
- server.js // entry point of app, define server
Node dependencies
Create a new file named package.json
with this content:
{
"name": "hapi-social-login",
"version": "1.0.0",
"description": "Simple project showing social login with hapijs and bell.",
"main": "server.js",
"private": true,
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": {
"bell": "^7.9.0",
"boom": "^3.1.1",
"hapi": "^13.4.1",
"hapi-auth-cookie": "^6.1.1"
}
}
So let's look at the packages used:
hapi
should be clearboom
is used for http friendly errorsbell
handles all the OAuth handshake with Twitter for us and makes integration a breezehapi-auth-cookie
provides a simple cookie-based session management
Now it is time to install our dependencies. Fire up your command line, navigate into the root directory of your app and type:
npm install
Create the server
The implementation is so simple so that I will post the whole code here at once and explain it afterwards. Create a new file named server.js
with this content:
'use strict';
const Hapi = require('hapi');
const Boom = require('boom');
// Create a server with a host and port
const server = new Hapi.Server();
server.connection({
port: 3000
});
// Register bell and hapi-auth-cookie with the server
server.register([require('hapi-auth-cookie'), require('bell')], function(err) {
//Setup the session strategy
server.auth.strategy('session', 'cookie', {
password: 'secret_cookie_encryption_password', //Use something more secure in production
redirectTo: '/auth/twitter', //If there is no session, redirect here
isSecure: false //Should be set to true (which is the default) in production
});
//Setup the social Twitter login strategy
server.auth.strategy('twitter', 'bell', {
provider: 'twitter',
password: 'secret_cookie_encryption_password', //Use something more secure in production
clientId: 'Here goes the twitter Consumer Key',
clientSecret: 'Here goes the twitter Consumer Secret',
isSecure: false //Should be set to true (which is the default) in production
});
//Setup the routes (this could be done in an own file but for the sake of simplicity isn't)
server.route({
method: 'GET',
path: '/auth/twitter',
config: {
auth: 'twitter', //<-- use our twitter strategy and let bell take over
handler: function(request, reply) {
if (!request.auth.isAuthenticated) {
return reply(Boom.unauthorized('Authentication failed: ' + request.auth.error.message));
}
//Just store a part of the twitter profile information in the session as an example. You could do something
//more useful here - like loading or setting up an account (social signup).
const profile = request.auth.credentials.profile;
request.cookieAuth.set({
twitterId: profile.id,
username: profile.username,
displayName: profile.displayName
});
return reply.redirect('/');
}
}
});
server.route({
method: 'GET',
path: '/',
config: {
auth: 'session', //<-- require a session for this, so we have access to the twitter profile
handler: function(request, reply) {
//Return a message using the information from the session
return reply('Hello, ' + request.auth.credentials.displayName + '!');
}
}
});
// Start the server
server.start((err) => {
if (err) {
throw err;
}
console.log('Server running at:', server.info.uri);
});
});
First to note is the code is heavily commented, so you should be able to understand it by just reading it. It is not exactly an useful application on it's own but serves as a playground for social login with hapi.
We register the plugins (bell
and haps-auth-cookie
) with the server. Then we setup two authentication strategies - one for a normal session and the other for the OAuth dance with Twitter. After that we create the routes and secure them with the right auth strategy. Finally we startup our server.
Important: To make the code work you have to copy the Consumer Key
and Consumer Secret
from your Twitter application and then add them to your version of the code in the twitter
auth strategy.
Route /
This route requires a session setup and welcomes the authenticated user with his Twitter name.
If there is no session it will redirect to /auth/twitter
...
Route /auth/twitter
This route handles the OAuth dance with Twitter. It redirects the user to Twitter and requests him to allow our application access to his profile data. This looks something similar to this:
After the user granted access he will be redirected back to our application where bell
fetches his Twitter profile and provides it to us via request.auth.credentials.profile
. We then store it in the session (if there is none it will be created) and redirect to /
where the user will be welcomed with his Twitter name.
At this point you could also do something else than storing the credentials in the session. You could create a user account in your database or check if this user has already logged in with Twitter by querying your database. So you can create a multi user application for example. Other use cases are also possible.
Step 3: Testing in the Browser
Now start the server:
node server.js
Fire up your Browser and navigate to http://localhost:3000
. You should be redirected to authenticate with your Twitter account. After successfully granting our app you should see the welcome message:
If you do reload this page the message stays there because of the session.
Code
You can download the complete code of this tutorial on Github.
You want to learn more?
I just created a new online video course on Udemy and offer a 50% discount to loyal readers of my blog...
All you have to do is to click on the course image above. The discount code is included in the link!
I'm happy to see you in the course...