Passport Authentication for Node.js Applications

In this tutorial, we’ll be implementing authentication via Facebook and GitHub in a Node.js web application. For this, we’ll be using Passport, an authentication middleware for Node.js. Passport supports authentication with OpenId/OAuth providers.

Express Web App

Before getting started, make sure you have Node.js installed on your machine.

We’ll begin by creating the folder for our app and then accessing that folder on the terminal:

mkdir AuthApp
cd AuthApp

To create the node app we’ll use the following command:

npm init

You’ll be prompted to provide some information for Node’s package.json. Just hit enter until the end to leave the default configuration.

Next, we’ll need an HTML file to send to the client. Create a file called auth.html in the root folder of your app, with the following contents:

<html>
  <head>
    <title>Node.js OAuth</title>
  </head>
  <body>
    <a href=auth/facebook>Sign in with Facebook</a>
    <br></br>
    <a href=auth/github>Sign in with Github</a>
  </body>
</html>

That’s all the HTML we’ll need for this tutorial.

You’ll also require Express, a framework for building web apps that’s inspired by Ruby’s Sinatra. In order to install Express, from the terminal type the following command:

npm install express --save

Once you’ve done that, it’s time to write some code.

Create a file index.js in the root folder of your app and add the following content to it:

/*  EXPRESS SETUP  */

const express = require('express');
const app = express();

app.get('/', (req, res) => res.sendFile('auth.html', { root : __dirname}));

const port = process.env.PORT || 3000;
app.listen(port , () => console.log('App listening on port ' + port));

In the code above, we require Express and create our Express app by calling express(). Then we declare the route for the home page of our app. There we send the HTML file we’ve created to the client accessing that route. Then, we use process.env.PORT to set the port to the environment port variable if it exists. Otherwise, we’ll default to 3000, which is the port we’ll be using locally. This gives you enough flexibility to switch from development, directly to a production environment where the port might be set by a service provider like, for instance, Heroku. Right below, we call app.listen() with the port variable we set up, and a simple log to let us know that it’s all working fine, and on which port is the app listening.

Now we should start our app to make sure all is working correctly. Simply write the following command on the terminal:

node index.js

You should see the message: App listening on port 3000. If that’s not the case, you probably missed a step. Go back and try again.

Moving on, let’s see if our page is being served to the client. Go to your web browser and navigate to http://localhost:3000.

If you can see the page we created in auth.html, we’re good to go.

Head back to the terminal and stop the app with ctrl + c. So remember, when I say start the app, you write node index.js, and when I say stop the app, you do ctrl + c. Clear? Good, you’ve just been programmed :-)

Setting up Passport

As you’ll soon come to realize, Passport makes it a breeze to provide authentication for our users. Let’s install Passport with the following command:

npm install passport --save

Now we have to set up Passport. Add the following code at the bottom of the index.js file:

/*  PASSPORT SETUP  */

const passport = require('passport');
app.use(passport.initialize());
app.use(passport.session());

app.get('/success', (req, res) => res.send("You have successfully logged in"));
app.get('/error', (req, res) => res.send("error logging in"));

passport.serializeUser(function(user, cb) {
  cb(null, user);
});

passport.deserializeUser(function(obj, cb) {
  cb(null, obj);
});

Here we require Passport and initialize it along with its session authentication middleware, directly inside our Express app. Then, we set up the '/success' and '/error' routes, which will render a message telling us how the authentication went. It’s the same syntax for our last route, only this time instead of using [res.SendFile()](http://expressjs.com/en/api.html#res.sendFile) we’re using [res.send()](http://expressjs.com/en/api.html#res.send), which will render the given string as text/html in the browser. Then we’re using serializeUser and deserializeUser callbacks. The first one will be invoked on authentication and its job is to serialize the user instance and store it in the session via a cookie. The second one will be invoked every subsequent request to deserialize the instance, providing it the unique cookie identifier as a “credential”. You can read more about that in the Passport documentation.

As a side note, this very simple sample app of ours will work just fine without deserializeUser, but it kills the purpose of keeping a session, which is something you’ll need in every app that requires login.

That’s all for the actual Passport setup. Now we can finally get onto business.

Implementing Facebook Authentication

The first thing we’ll need to do in order to provide Facebook Authentication is installing the passport-facebook package. You know how it goes:

npm install passport-facebook --save

Now that everything’s set up, adding Facebook Authentication is extremely easy. Add the following code at the bottom of your index.js file:

/*  FACEBOOK AUTH  */

const FacebookStrategy = require('passport-facebook').Strategy;

const FACEBOOK_APP_ID = 'your app id';
const FACEBOOK_APP_SECRET = 'your app secret';

passport.use(new FacebookStrategy({
    clientID: FACEBOOK_APP_ID,
    clientSecret: FACEBOOK_APP_SECRET,
    callbackURL: "/auth/facebook/callback"
  },
  function(accessToken, refreshToken, profile, cb) {
      return cb(null, profile);
  }
));

app.get('/auth/facebook',
  passport.authenticate('facebook'));

app.get('/auth/facebook/callback',
  passport.authenticate('facebook', { failureRedirect: '/error' }),
  function(req, res) {
    res.redirect('/success');
  });

Let’s go through this block of code step by step. First, we require the passport-facebook module. Then, we declare the variables in which we’ll store our app id and app secret (we’ll see how to get those shortly). After that, we tell Passport to use an instance of the FacebookStrategy we required. To instantiate said strategy we give it our app id and app secret variables and the callbackURL that we’ll use to authenticate the user. As a second parameter, it takes a function that will return the profile info provided by the user.

Further down, we set up the routes to provide authentication. As you can see in the callbackURL we redirect the user to the /error and /success routes we defined earlier. We’re using passport.authenticate, which attempts to authenticate with the given strategy on its first parameter, in this case facebook. You probably noticed that we’re doing this twice. On the first one, it sends the request to our Facebook app. The second one is triggered by the callback URL, which Facebook will use to respond to the login request.

Now you’ll need to create a Facebook app. For details on how to do that, consult Facebook’s very detailed guide Creating a Facebook App, which provides step by step instructions on how to create one.

When your app is created, go to Settings on the app configuration page. There you’ll see your app id and app secret. Don’t forget to change the variables you declared for them on the index.js file with their corresponding values.

Next, enter “localhost” in the App Domains field. Then, go to Add platform at the bottom of the page and choose Website. Use http://localhost:3000/auth/facebook/callback as the Site URL.

On the left sidebar, under the Products section, you should see Facebook Login. Click to get in there.

Lastly, set the Valid OAuth redirect URIs field to http://localhost:3000/auth/facebook/callback.

If you start the app now and click the Sign in with Facebook link, you should be prompted by Facebook to provide the required information, and after you’ve logged in, you should be redirected to the /success route, where you’ll see the message You have successfully logged in.

That’s it! you have just set up Facebook Authentication. Pretty easy, right?

Implementing GitHub Authentication

The process for adding GitHub Authentication is quite similar to what we did for Facebook. First, we’ll install the passport-github module:

npm install passport-github --save

Now go to the index.js file and add the following lines at the bottom:

/*  GITHUB AUTH  */

const GitHubStrategy = require('passport-github').Strategy;

const GITHUB_CLIENT_ID = "your app id"
const GITHUB_CLIENT_SECRET = "your app secret";

passport.use(new GitHubStrategy({
    clientID: GITHUB_CLIENT_ID,
    clientSecret: GITHUB_CLIENT_SECRET,
    callbackURL: "/auth/github/callback"
  },
  function(accessToken, refreshToken, profile, cb) {
      return cb(null, profile);
  }
));

app.get('/auth/github',
  passport.authenticate('github'));

app.get('/auth/github/callback',
  passport.authenticate('github', { failureRedirect: '/error' }),
  function(req, res) {
    res.redirect('/success');
  });

This looks familiar! It’s practically the same as before. The only difference is that we’re using the GithubStrategy instead of FacebookStrategy.

So far so … the same. In case you hadn’t yet figured it out, the next step is to create our GitHub App. GitHub has a very simple guide, Creating a GitHub app, that will guide you through the process.

When you’re done, in the configuration panel you’ll need to set the Homepage URL to http://localhost:3000/ and the Authorization callback URL to http://localhost:3000/auth/github/callback, just like we did with Facebook.

Now, simply restart the Node server and try logging in using the GitHub link.

It works! Now you can let your users log in with GitHub.

Conclusion

In this tutorial, we saw how Passport made the task of authentication quite simple. Implementing Google and Twitter authentication follows a nearly identical pattern. I challenge you to implement these using the passport-google and passport-twitter modules. In the meantime, the code for this app is available on GitHub.

Sponsors