Easy Node Authentication: Google

Free Course

Build Your First Node.js Website

Node is a powerful tool to get JavaScript on the server. Use Node to build a great website.

Welcome to Part 4 of our Easy Node Authentication with Passport series. We will be using the foundation of that tutorial to use Google authentication with our application. We already have a good application structure for our application packages, user model, application setup and views. node-auth-google-index Since we set up our application to be as clean and efficient as possible, we will only have to create our Google application and add to 4 different files:

Creating the Google App, Client ID, and Client Secret config/auth.js
Configuring the Passport Google Strategy config/passport.js
Generating Routes app/routes.js
Updating Views views/

Since we are already familiar with code organization (the first tutorial) and where we need to add code to authenticate with a social network (the second tutorial), we’ll jump right into configuring our Passport Google Strategy.

Authenticating with Google using Passport

Creating Our Google Application

The place to create Google applications can be found at their Cloud API Console. Applications can be found under Project > APIs & auth.

Let’s go ahead and create our application with the correct redirect URL: http://localhost:8080/auth/google/callback.

If Google doesn’t like http://localhost:8080, then use http://127.0.0.1:8080.

node-auth-google-credentials Let’s add our Client ID and our client secret to our auth.js file so that our application knows the secrets it needs to authenticate with Google.

// config/auth.js

// expose our config directly to our application using module.exports
module.exports = {

    'facebookAuth' : {
        'clientID'      : 'your-secret-clientID-here', // your App ID
        'clientSecret'  : 'your-client-secret-here', // your App Secret
        'callbackURL'   : 'http://localhost:8080/auth/facebook/callback'
    },

    'twitterAuth' : {
        'consumerKey'       : 'your-consumer-key-here',
        'consumerSecret'    : 'your-client-secret-here',
        'callbackURL'       : 'http://localhost:8080/auth/twitter/callback'
    },

    'googleAuth' : {
        'clientID'      : 'your-secret-clientID-here',
        'clientSecret'  : 'your-client-secret-here',
        'callbackURL'   : 'http://localhost:8080/auth/google/callback'
    }

};

Customizing Your Application Screen

Google let’s you change the default login screen so that you can customize it with your brand’s logo and text. This can be found on the same page where your client ID and secret are. The option is under Consent Screen.

Here is the customization screen:

node-auth-google-customization With our application ready to go, let’s set up our Passport Google Strategy.

Configuring Passport’s Google Strategy config/passport.js

We will be using the passport-google-oauth package by Jared Hanson so that we can authenticate with OAuth2.

There will be comments as placeholders for the previous article’s strategies.

// config/passport.js

// load all the things we need
var LocalStrategy    = require('passport-local').Strategy;
var FacebookStrategy = require('passport-facebook').Strategy;
var TwitterStrategy  = require('passport-twitter').Strategy;
var GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;

// load up the user model
var User       = require('../app/models/user');

// load the auth variables
var configAuth = require('./auth');

module.exports = function(passport) {

    // used to serialize the user for the session
    passport.serializeUser(function(user, done) {
        done(null, user.id);
    });

    // used to deserialize the user
    passport.deserializeUser(function(id, done) {
        User.findById(id, function(err, user) {
            done(err, user);
        });
    });
    
    // code for login (use('local-login', new LocalStategy))
    // code for signup (use('local-signup', new LocalStategy))
    // code for facebook (use('facebook', new FacebookStrategy))
    // code for twitter (use('twitter', new TwitterStrategy))

    // =========================================================================
    // GOOGLE ==================================================================
    // =========================================================================
    passport.use(new GoogleStrategy({

        clientID        : configAuth.googleAuth.clientID,
        clientSecret    : configAuth.googleAuth.clientSecret,
        callbackURL     : configAuth.googleAuth.callbackURL,

    },
    function(token, refreshToken, profile, done) {

        // make the code asynchronous
        // User.findOne won't fire until we have all our data back from Google
        process.nextTick(function() {

            // try to find the user based on their google id
            User.findOne({ 'google.id' : profile.id }, function(err, user) {
                if (err)
                    return done(err);

                if (user) {

                    // if a user is found, log them in
                    return done(null, user);
                } else {
                    // if the user isnt in our database, create a new user
                    var newUser          = new User();

                    // set all of the relevant information
                    newUser.google.id    = profile.id;
                    newUser.google.token = token;
                    newUser.google.name  = profile.displayName;
                    newUser.google.email = profile.emails[0].value; // pull the first email

                    // save the user
                    newUser.save(function(err) {
                        if (err)
                            throw err;
                        return done(null, newUser);
                    });
                }
            });
        });

    }));

};


Now we have the Google Strategy that will search for a user based on their google.id that corresponds to their profile.id we get back from Google. Next let’s handle our routes to use our new Strategy.

Generating Our Routes app/routes.js

We will need 2 routes.

  • /auth/google: Send our user to Google to authenticate
  • /auth/google/callback: Google sends our user back to our application with token and profile
// app/routes.js

module.exports = function(app, passport) {

    // route for home page
    app.get('/', function(req, res) {
        res.render('index.ejs'); // load the index.ejs file
    });

    // route for login form
    // route for processing the login form
    // route for signup form
    // route for processing the signup form

    // route for showing the profile page
    app.get('/profile', isLoggedIn, function(req, res) {
        res.render('profile.ejs', {
            user : req.user // get the user out of session and pass to template
        });
    });

    // route for logging out
    app.get('/logout', function(req, res) {
        req.logout();
        res.redirect('/');
    });

    // facebook routes
    // twitter routes

    // =====================================
    // GOOGLE ROUTES =======================
    // =====================================
    // send to google to do the authentication
    // profile gets us their basic information including their name
    // email gets their emails
    app.get('/auth/google', passport.authenticate('google', { scope : ['profile', 'email'] }));

    // the callback after google has authenticated the user
    app.get('/auth/google/callback',
            passport.authenticate('google', {
                    successRedirect : '/profile',
                    failureRedirect : '/'
            }));

};

// route middleware to make sure a user is logged in
function isLoggedIn(req, res, next) {

    // if user is authenticated in the session, carry on
    if (req.isAuthenticated())
        return next();

    // if they aren't redirect them to the home page
    res.redirect('/');
}

Our routes are very simple. Just authenticate and handle the callback.

Showing Our User index.ejs, profile.ejs

Once a user is authenticated, they will be redirected to their profile page. Last thing we need to do is show their user information.

Google Login Button views/index.ejs

Let’s create the Google login button.

<!-- views/index.ejs -->

<!doctype html>
<html>
<head>
    <title>Node Authentication</title>
    <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.2/css/bootstrap.min.css"> <!-- load bootstrap css -->
    <link rel="stylesheet" href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css"> <!-- load fontawesome -->
    <style>
        body        { padding-top:80px; }
    </style>
</head>
<body>
<div class="container">

    <div class="jumbotron text-center">
        <h1><span class="fa fa-lock"></span> Node Authentication</h1>

        <p>Login or Register with:</p>

        <a href="/auth/google" class="btn btn-danger"><span class="fa fa-google-plus"></span> Google</a>

    </div>

</div>
</body>
</html>   

node-auth-google-index When a user clicks on our authentication link, they will be directed to Google. A user will have to login and then grant permissions.

node-auth-google-signin
node-auth-google-accept

Profile Page views/profile.ejs

Once a user registers, they will be added to our database. Let’s show their user information.

<!-- views/profile.ejs -->
<!doctype html>
<html>
<head>
    <title>Node Authentication</title>
    <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.2/css/bootstrap.min.css">
    <link rel="stylesheet" href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css">
    <style>
        body        { padding-top:80px; word-wrap:break-word; }
    </style>
</head>
<body>
<div class="container">

    <div class="page-header text-center">
        <h1><span class="fa fa-anchor"></span> Profile Page</h1>
        <a href="/logout" class="btn btn-default btn-sm">Logout</a>
    </div>

    <div class="row">

        <!-- GOOGLE INFORMATION -->
        <div class="col-sm-6">
            <div class="well">
                <h3 class="text-danger"><span class="fa fa-google-plus"></span> Google</h3>

                    <p>
                        <strong>id</strong>: <%= user.google.id %><br>
                        <strong>token</strong>: <%= user.google.token %><br>
                        <strong>email</strong>: <%= user.google.email %><br>
                        <strong>name</strong>: <%= user.google.name %>
                    </p>

            </div>
        </div>

    </div>

</div>
</body>
</html>

Now we have their profile page!

node-auth-google-profile

All Done!

Just like the other articles in this series, it is fairly straightforward to authenticate a user using a social network and OAuth 2.0.

In our next and final article, we will be dealing with the giant task of combining all of these methods of authentication into one user.

We’ll be diving into many ideas like linking social accounts under one user, unlinking an account, and handling all the other complex scenarios involved with this process.

Chris Sevilleja

Co-founder of Scotch.io. Slapping the keyboard until something good happens.