This tutorial is out of date and no longer maintained.
Note: This article is part of our Easy Node Authentication series.
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:
config/auth.js
)config/passport.js
)app/routes.js
)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.
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
.
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'
}
};
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:
With our application ready to go, let’s set up our Passport Google Strategy.
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.
We will need 2 routes.
// 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.
Once a user is authenticated, they will be redirected to their profile page. Last thing we need to do is show their user information.
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>
When a user clicks on our authentication link, they will be directed to Google. A user will have to login and then grant permissions.
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!
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.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!