In this article, I’m explaining to create the local authentication with passport.js and also this account with all social accounts like Facebook, twitter, and google+. In this article, use the application ejs template engine for express application.
Authentication and logins in Node may be a sophisticated factor. Truly work sure any application may be a pain. This text series can influence authenticating in your Node application victimization the package Passport.
Passport is authentication middleware for Node. It’s designed to serve a singular purpose: evidence requests. Once writing modules, encapsulation could be a virtue, therefore Passport delegates all alternative practicality to the appliance. This separation of issues keeps code clean and reparable, associate degreed makes Passport very simple to integrate into an application.
In modern web applications, authentication can take a variety of forms. Traditionally, users log in by providing a username and password. With the rise of social networking, single sign-on using an OAuth provider such as Facebook or Twitter has become a popular authentication method. Services that expose an API often require token-based credentials to protect access.
Here, I’m creating the application. In this application we’ll be building the following things:
· Local account login and signup (using passport-local)
· Facebook login and registration (using passport-facebook)
· Twitter login and registration (using passport-twitter)
· Google+ login and registration (using oauth with passport-google-oauth)
These all things develop in this article. This application needs to install the api. To set up our base Node application, we’ll need a few things. We’ll set up our npm packages, node application, configuration files, models, and routes.
First need to create an application for the authentication. As old created application create the application by express command.
Step 1 Folder Structure of the Application
In this application what is the project structure. The structure of this application as like this:
-app
------model it contains models
-----------user_models.js all schema for all data items
------route.js all the routes for application
-config This folder contain the configuration folder
-------authentication.js will hold all client secret keys (Facebook, twitter, google)
-------database.js configure database for
-------passport.js configuring the strategies for passport
-data data folder contain the database
-views
-------home.ejs show home page with login links
-------user_login.ejs show login form
-------user_profile.ejs after a user logs in, they will see their profile
-------user_registration.ejs show signup form
-package.json install all necessary npm packages
-app.js setup our application it is the entry point file
Let’s create all these folder and files according to the directory structure. And others items remove to best understand the passport authentication.
Step 2 Install Dependency
After create all the folder and files according to folder structure. Now install the dependency. Some necessary packages that shuld be install. Let’s know some necessary packages that install in the application:
· Express is the framework.
· Ejs is the templating engine or view engine.
· Mongoose is object modeling for our MongoDB database.
· Passport stuff will help us authenticating with different methods.
· Connect-flash allows for passing session flash data messages.
· Bcrypt-nodejs gives us the ability to hash the password. I use bcrypt-nodejs instead of bcrypt since it is easier to set up in windows.
Let’s add the all necessary package with its dependency.
{
"name": "NodeAuthenticatuionWithAll",
"version": "0.0.1",
"main":"app.js",
"dependencies": {
"express" : "~3.4.4",
"ejs" : "~0.8.5",
"mongoose" : "~3.8.1",
"passport" : "~0.1.17",
"passport-local" : "~0.1.6",
"passport-facebook" : "~1.0.2",
"passport-twitter" : "~1.0.2",
"passport-google-oauth" : "~0.1.5",
"connect-flash" : "~0.1.1",
"bcrypt-nodejs" : "latest"
}
}
After add all dependencies now need to install it without installation of all these packages it’s not working. All dependencies install by the npm install command.
Step 3 Add app.js for Application Setup
This is the entry point of the application. It make all packages work together in the application. The app.js goal to set up all the packages to the entire application.
// app.js
// get all the tools we need
var express = require('express');
var mongoose = require('mongoose');
var passport = require('passport');
var flash = require('connect-flash');
var configDB = require('./config/database.js');
var app = express();
var port = process.env.PORT || 8080;
// configuration
mongoose.connect(configDB.url); // connect to our database
require('./config/passport')(passport); // pass passport for configuration
app.configure(function() {
// express application configuration
app.use(express.logger('dev')); // log every request to the console
app.use(express.cookieParser()); // read cookies need for the authenticatiom
app.use(express.bodyParser()); // get information from html forms
app.set('view engine', 'ejs'); // set up ejs for templating
// required for passport
app.use(express.session({ secret: 'mindstickarticles' })); //create sessin mindsticarticle
app.use(passport.initialize()); // passport intialize
app.use(passport.session()); // persistent login sessions of passport
app.use(flash()); // use connect-flash for flash messages stored in session
});
// load our routes for work routes file
require('./app/routes.js')(app, passport); // load our routes and pass in our app and fully configured passport
// launch the application at port 8080
app.listen(port); // it listen at port 8080
console.log('Application running on port: ' + port);
This basically a simple program to run the application and add the packages. Now this file run as the node app.js command.
After start the application running we look up at the http://localhost:8080/ it’s running but this time nothing output because no code for view or it may be give error because not configure database. So add the database configuration.
Step 3 Configure Database
Configure database step to ready to run the successfully application. In this example connection database with the MongoDB. Let set the database in the /config/database.js file:
// config/database.js
module.exports = {
'url' : 'your database here’ // looks like mongodb://localhost:27017/NodeAuthenticationWithAll
};
This set the database in the application. This database easy pass in the app.js and configure it.
Step 4 Create Views
Views are the thing that show our user interface. Create view for the home page, login page, signup page, and profile page after login show. Let’s create pages with the bootstrap:
/views/home.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; }
</style>
</head>
<body>
<div class="container">
<div class="col-sm-6 col-sm-offset-3">
<div class="page-header">
<h1 class="text-success"><span class="glyphicon glyphicon-lock"></span> User Authentication</h1>
<p><small class="text-info">Login or Register with:<small></p>
</div >
<a href="/login" class="btn btn-default"><span class="fa fa-user"></span> Local Login</a><br><br>
<a href="/register" class="btn btn-default"><span class="fa fa-user"></span> Local Signup</a><br><br>
<a href="/auth/facebook" class="btn btn-primary"><span class="fa fa-facebook"></span> Facebook</a><br><br>
<a href="/auth/twitter" class="btn btn-info"><span class="fa fa-twitter"></span> Twitter</a><br><br>
<a href="/auth/google" class="btn btn-danger"><span class="fa fa-google-plus"></span> Google+</a><br><br>
</div>
</div>
</body>
</html>
Now if you go to the browser then application is look like this:
Now create the login page for the local login:
/view/user_login.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; }
</style>
</head>
<body>
<div class="container">
<div class="col-sm-6 col-sm-offset-3">
<h1 class="text-info"><span class="fa fa-sign-in"></span> Login</h1>
<% if (message.length > 0) { %>
<div class="alert alert-warning"><%= message %></div>
<% } %>
<!-- LOGIN FORM -->
<form action="/login" method="post">
<div class="form-group">
<label>Email</label>
<input type="text" class="form-control" name="email" placeholder="email or user name">
</div>
<div class="form-group">
<label>Password</label>
<input type="password" class="form-control" name="password" placeholder="password">
</div>
<button type="submit" class="btn btn-danger btn-lg">Login</button>
</form>
<hr>
<p>Need an account? <a href="/register">Signup</a> | <a href="/">home</a>.</p>
</div>
</div>
</body>
</html>
This is look like the as like this:
It login the locally. After that create the user register page or local user registration page.
/views/user_registration.jade
<!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; }
</style>
</head>
<body>
<div class="container">
<div class="col-sm-6 col-sm-offset-3">
<h1 class="text-info"><span class="fa fa-sign-in"></span> Signup</h1>
<% if (message.length > 0) { %>
<div class="alert alert-danger"><%= message %></div>
<% } %>
<!-- LOGIN FORM -->
<form action="/register" method="post">
<div class="form-group">
<label>Email</label>
<input type="text" class="form-control" name="email" placeholder="email or user name">
</div>
<div class="form-group">
<label>Password</label>
<input type="password" class="form-control" name="password" placeholder="password">
</div>
<button type="submit" class="btn btn-danger btn-lg">Signup</button>
</form>
<hr>
<p>Already have an account? <a href="/login">Login</a> | <a href="/">home</a>.</p>
</div>
</div>
</body>
</html>
This will user register as local and now create a page to show all logins:
/views/user_profile.jade
<!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 class="text-info"><li class="fa fa-user"></li> User Profile Page</h1>
<a href="/logout" class="btn btn-default btn-sm">Logout</a>
</div>
<div class="row">
<!-- LOCAL INFORMATION -->
<div class="col-sm-6">
<div class="well">
<h3><span class="fa fa-user"></span> Local</h3>
<% if (user.local.email) { %>
<p>strong>id</strong>: <%= user._id %>
<br>
<strong>email</strong>: <%= user.local.email %><br>
<strong>password</strong>: <%= user.local.password %>
</p>
<a href="/unlink/local" class="btn btn-default">Unlink</a>
<% } else { %>
<a href="/connect/local" class="btn btn-default">Connect Local</a>
<% } %>
</div>
</div>
<!-- FACEBOOK INFORMATION -->
<div class="col-sm-6">
<div class="well">
<h3 class="text-primary"><span class="fa fa-facebook"></span> Facebook</h3>
<!-- check if the user has this token (is the user authenticated with this social account) -->
<% if (user.facebook.token) { %>
<p>
<strong>id</strong>: <%= user.facebook.id %><br>
<strong>token</strong>: <%= user.facebook.token %><br>
<strong>email</strong>: <%= user.facebook.email %><br>
<strong>name</strong>: <%= user.facebook.name %><br>
</p>
<a href="/unlink/facebook" class="btn btn-primary">Unlink</a>
<% } else { %>
<a href="/connect/facebook" class="btn btn-primary">Connect Facebook</a>
<% } %>
</div>
</div>
</div>
<div class="row">
<!-- TWITTER INFORMATION -->
<div class="col-sm-6">
<div class="well">
<h3 class="text-info"><span class="fa fa-twitter"></span> Twitter</h3>
<% if (user.twitter.token) { %>
<p>
<strong>id</strong>: <%= user.twitter.id %><br>
<strong>token</strong>: <%= user.twitter.token %><br>
<strong>display name</strong>: <%= user.twitter.displayName %><br>
<strong>username</strong>: <%= user.twitter.username %>
</p>
<a href="/unlink/twitter" class="btn btn-info">Unlink</a>
<% } else { %>
<a href="/connect/twitter" class="btn btn-info">Connect Twitter</a>
<% } %>
</div>
</div>
<!-- GOOGLE INFORMATION -->
<div class="col-sm-6">
<div class="well">
<h3 class="text-danger"><span class="fa fa-google-plus"></span> Google+</h3>
<% if (user.google.token) { %>
<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>
<a href="/unlink/google" class="btn btn-danger">Unlink</a>
<% } else { %>
<a href="/connect/google" class="btn btn-danger">Connect Google</a>
<% } %>
</div>
</div>
</div>
</div>
</body>
</html>
This page was look as like this that after login:
Now we need to add its function. So now need to add its models.
Step 5 Create User Model
Model is very necessary for the logic implementation. Now create the User models for the local, facebook, twitter and google+. For local we need the email and password and the social account need to id, token, displayname, and username.
If you want to any change you should be change in the /app/user_models.js file:
// load the things we need
var mongoose = require('mongoose');
var bcrypt = require('bcrypt-nodejs');
// define the schema for our user model
var userSchema = mongoose.Schema({
local : {
email : String,
password : String,
},
facebook : {
id : String,
token : String,
email : String,
name : String
},
twitter : {
id : String,
token : String,
displayName : String,
username : String
},
google : {
id : String,
token : String,
email : String,
name : String
}
});
// generating a hash
userSchema.methods.generateHash = function(password) {
return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);
};
// checking if password is valid
userSchema.methods.validPassword = function(password) {
return bcrypt.compareSync(password, this.local.password);
};
// create the model for users and expose it to our app
module.exports = mongoose.model('User', userSchema);
Create the user models for User schema. Now generate the hash password automatically. Now need to authentication that will necessary to first add the routes after working all authentication mechanisms.
Step 6 Create Route
Route is that part connect your user interface with the application logic. Route can contain both GET and POST method. In this example need to many route for the application as like:
/app/routes.js
module.exports = function(app, passport) {
// show the home page (will also have our login links)
app.get('/', function(req, res) {
res.render('home.ejs');
});
// PROFILE SECTION
app.get('/profile', isLoggedIn, function(req, res) {
res.render('user_profile.ejs', {
user : req.user
});
});
// LOGOUT
app.get('/logout', function(req, res) {
req.logout();
res.redirect('/');
});
-----------------Authenticate login-----------
// show the login form
app.get('/login', function(req, res) {
res.render('user_login.ejs', { message: req.flash('loginMessage') });
});
// process the login form
app.post('/login', passport.authenticate('local-login', {
successRedirect : '/profile', // redirect to the secure profile section
failureRedirect : '/login', // redirect back to the signup page if there is an error
failureFlash : true // allow flash messages
}));
----------------User Regitration------
// show the signup form
app.get('/register', function(req, res) {
res.render('user_registration.ejs', { message: req.flash('loginMessage') });
});
// process the signup form
app.post('/register', passport.authenticate('local-signup', {
successRedirect : '/profile', // redirect to the secure profile section
failureRedirect : '/register', // redirect back to the signup page if there is an error
failureFlash : true // allow flash messages
}));
// send to facebook to do the authentication
app.get('/auth/facebook', passport.authenticate('facebook', { scope : 'email' }));
// handle the callback after facebook has authenticated the user
app.get('/auth/facebook/callback',
passport.authenticate('facebook', {
successRedirect : '/profile',
failureRedirect : '/'
}));
// send to twitter to do the authentication
app.get('/auth/twitter', passport.authenticate('twitter', { scope : 'email' }));
// handle the callback after twitter has authenticated the user
app.get('/auth/twitter/callback',
passport.authenticate('twitter', {
successRedirect : '/profile',
failureRedirect : '/'
}));
--------------google ----
// send to google to do the authentication
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 : '/'
}));
---------------Authorizing already logining
// local login
app.get('/connect/local', function(req, res) {
res.render('connect-local.ejs', { message: req.flash('loginMessage') });
});
app.post('/connect/local', passport.authenticate('local-signup', {
successRedirect : '/profile', // redirect to the secure profile section
failureRedirect : '/connect/local', // redirect back to the signup page if there is an error
failureFlash : true // allow flash messages
}));
// send to facebook to do the authentication
app.get('/connect/facebook', passport.authorize('facebook', { scope : 'email' }));
// handle the callback after facebook has authorized the user
app.get('/connect/facebook/callback',
passport.authorize('facebook', {
successRedirect : '/profile',
failureRedirect : '/'
}));
// send to twitter to do the authentication
app.get('/connect/twitter', passport.authorize('twitter', { scope : 'email' }));
// handle the callback after twitter has authorized the user
app.get('/connect/twitter/callback',
passport.authorize('twitter', {
successRedirect : '/profile',
failureRedirect : '/'
}));
// send to google to do the authentication
app.get('/connect/google', passport.authorize('google', { scope : ['profile', 'email'] }));
// the callback after google has authorized the user
app.get('/connect/google/callback',
passport.authorize('google', {
successRedirect : '/profile',
failureRedirect : '/'
}));
---------------Unlink Account
/* used to unlink accounts. for social accounts, just remove the token
for local account, remove email and password
user account will stay active in case they want to reconnect in the future
*/
// local login
app.get('/unlink/local', function(req, res) {
var user = req.user;
user.local.email = undefined;
user.local.password = undefined;
user.save(function(err) {
res.redirect('/profile');
});
});
// facebook -------------------------------
app.get('/unlink/facebook', function(req, res) {
var user = req.user;
user.facebook.token = undefined;
user.save(function(err) {
res.redirect('/profile');
});
});
// twitter --------------------------------
app.get('/unlink/twitter', function(req, res) {
var user = req.user;
user.twitter.token = undefined;
user.save(function(err) {
res.redirect('/profile');
});
});
// google ---------------------------------
app.get('/unlink/google', function(req, res) {
var user = req.user;
user.google.token = undefined;
user.save(function(err) {
res.redirect('/profile');
});
});
};
// route middleware to ensure user is logged in
function isLoggedIn(req, res, next) {
if (req.isAuthenticated())
return next();
res.redirect('/');
}
On the creation of route implement all route of the page and decide when page move to another page. In the above create all routes either ‘/’ home page or ‘/login’ login or ‘/register’ signup or ‘/profile’ after login or facebook , twitter or google+ route all handle by the get or post route.
Step 7 Handle Authentication
First of all you will need to set the authentication variable that connect with social accounts.
Let’s add all the api code or seceret key to connect it:
// config/auth.js
// expose our config directly to our application using module.exports
module.exports = {
'facebookAuth' : {
'clientID' : 'your secret client id', // your App ID
'clientSecret' : 'your secret id', // your App Secret
'callbackURL' : 'http://localhost:8080/auth/facebook/callback'
},
'twitterAuth' : {
'consumerKey' : ' your secret client id'',
'consumerSecret' : ' your secret id ',
'callbackURL' : 'http://localhost:8080/auth/twitter/callback'
},
'googleAuth' : {
'clientID' : your secret client id'',
'clientSecret' : ' your secret id ',
'callbackURL' : 'http://localhost:8080/auth/google/callback'
}
};
It is necessary to connect with social accounts.
In the config folder /config/passport.js file that work because here authenticate all users:
· passport-local : it use for the local passport local authentication
· passport-facebook: it use for the facebook passport facebook authentication
· passport-twitter: it use for the twitter passport twitter authentication
· passport-google-oauth: it use for the google+ passport google+ authentication
It all use for authentication help in the authentication. All these modules are under the passport module. Let’s create the authentication for local, facebook, twitter, and google+.
// load all modules
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_models');
// load the authentication variables
var configAuth = require('./authentication'); // use this one for testing
module.exports = function(passport) {
passport session setup ==================================================
/*required for persistent login sessions
passport needs ability to serialize and unserialize users out of session
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);
});
});
LOCAL LOGIN =============================================================
passport.use('local-login', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField : 'email',
passwordField : 'password',
passReqToCallback : true // allows us to pass in the req from our route (lets us check if a user is logged in or not)
},
function(req, email, password, done) {
// asynchronous
process.nextTick(function() {
User.findOne({ 'local.email' : email }, function(err, user) {
// if there are any errors, return the error
if (err)
return done(err);
// if no user is found, return the message
if (!user)
return done(null, false, req.flash('loginMessage', 'No user found.'));
if (!user.validPassword(password))
return done(null, false, req.flash('loginMessage', 'Oops! Wrong password.'));
// all is well, return user
else
return done(null, user);
});
});
}));
LOCAL SIGNUP ============================================================
passport.use('local-signup', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField : 'email',
passwordField : 'password',
passReqToCallback : true // allows us to pass in the req from our route (lets us check if a user is logged in or not)
},
function(req, email, password, done) {
// asynchronous
process.nextTick(function() {
// Whether we're signing up or connecting an account, we'll need
// to know if the email address is in use.
User.findOne({'local.email': email}, function(err, existingUser) {
// if there are any errors, return the error
if (err)
return done(err);
// check to see if there's already a user with that email
if (existingUser)
return done(null, false, req.flash('signupMessage', 'That email is already taken.'));
// If we're logged in, we're connecting a new local account.
if(req.user) {
var user = req.user;
user.local.email = email;
user.local.password = user.generateHash(password);
user.save(function(err) {
if (err)
throw err;
return done(null, user);
});
}
// We're not logged in, so we're creating a brand new user.
else {
// create the user
var newUser = new User();
newUser.local.email = email;
newUser.local.password = newUser.generateHash(password);
newUser.save(function(err) {
if (err)
throw err;
return done(null, newUser);
});
}
});
});
}));
FACEBOOK ================================================================
passport.use(new FacebookStrategy({
clientID : configAuth.facebookAuth.clientID,
clientSecret : configAuth.facebookAuth.clientSecret,
callbackURL : configAuth.facebookAuth.callbackURL,
passReqToCallback : true // allows us to pass in the req from our route (lets us check if a user is logged in or not)
},
function(req, token, refreshToken, profile, done) {
// asynchronous
process.nextTick(function() {
// check if the user is already logged in
if (!req.user) {
User.findOne({ 'facebook.id' : profile.id }, function(err, user) {
if (err)
return done(err);
if (user) {
// if there is a user id already but no token (user was linked at one point and then removed)
if (!user.facebook.token) {
user.facebook.token = token;
user.facebook.name = profile.name.givenName + ' ' + profile.name.familyName;
user.facebook.email = profile.emails[0].value;
user.save(function(err) {
if (err)
throw err;
return done(null, user);
});
}
return done(null, user); // user found, return that user
} else {
// if there is no user, create them
var newUser = new User();
newUser.facebook.id = profile.id;
newUser.facebook.token = token;
newUser.facebook.name = profile.name.givenName + ' ' + profile.name.familyName;
newUser.facebook.email = profile.emails[0].value;
newUser.save(function(err) {
if (err)
throw err;
return done(null, newUser);
});
}
});
} else {
// user already exists and is logged in, we have to link accounts
var user = req.user; // pull the user out of the session
user.facebook.id = profile.id;
user.facebook.token = token;
user.facebook.name = profile.name.givenName + ' ' + profile.name.familyName;
user.facebook.email = profile.emails[0].value;
user.save(function(err) {
if (err)
throw err;
return done(null, user);
});
}
});
}));
// TWITTER =================================================================
passport.use(new TwitterStrategy({
consumerKey : configAuth.twitterAuth.consumerKey,
consumerSecret : configAuth.twitterAuth.consumerSecret,
callbackURL : configAuth.twitterAuth.callbackURL,
passReqToCallback : true // allows us to pass in the req from our route (lets us check if a user is logged in or not)
},
function(req, token, tokenSecret, profile, done) {
// asynchronous
process.nextTick(function() {
// check if the user is already logged in
if (!req.user) {
User.findOne({ 'twitter.id' : profile.id }, function(err, user) {
if (err)
return done(err);
if (user) {
// if there is a user id already but no token (user was linked at one point and then removed)
if (!user.twitter.token) {
user.twitter.token = token;
user.twitter.username = profile.username;
user.twitter.displayName = profile.displayName;
user.save(function(err) {
if (err)
throw err;
return done(null, user);
});
}
return done(null, user); // user found, return that user
} else {
// if there is no user, create them
var newUser = new User();
newUser.twitter.id = profile.id;
newUser.twitter.token = token;
newUser.twitter.username = profile.username;
newUser.twitter.displayName = profile.displayName;
newUser.save(function(err) {
if (err)
throw err;
return done(null, newUser);
});
}
});
} else {
// user already exists and is logged in, we have to link accounts
var user = req.user; // pull the user out of the session
user.twitter.id = profile.id;
user.twitter.token = token;
user.twitter.username = profile.username;
user.twitter.displayName = profile.displayName;
user.save(function(err) {
if (err)
throw err;
return done(null, user);
});
}
});
}));
// GOOGLE ==================================================================
passport.use(new GoogleStrategy({
clientID : configAuth.googleAuth.clientID,
clientSecret : configAuth.googleAuth.clientSecret,
callbackURL : configAuth.googleAuth.callbackURL,
passReqToCallback : true // allows us to pass in the req from our route (lets us check if a user is logged in or not)
},
function(req, token, refreshToken, profile, done) {
// asynchronous
process.nextTick(function() {
// check if the user is already logged in
if (!req.user) {
User.findOne({ 'google.id' : profile.id }, function(err, user) {
if (err)
return done(err);
if (user) {
// if there is a user id already but no token (user was linked at one point and then removed)
if (!user.google.token) {
user.google.token = token;
user.google.name = profile.displayName;
user.google.email = profile.emails[0].value; // pull the first email
user.save(function(err) {
if (err)
throw err;
return done(null, user);
});
}
return done(null, user);
} else {
var newUser = new User();
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
newUser.save(function(err) {
if (err)
throw err;
return done(null, newUser);
});
}
});
} else {
// user already exists and is logged in, we have to link accounts
var user = req.user; // pull the user out of the session
user.google.id = profile.id;
user.google.token = token;
user.google.name = profile.displayName;
user.google.email = profile.emails[0].value; // pull the first email
user.save(function(err) {
if (err)
throw err;
return done(null, user);
});
}
});
}));
};
These all things give the strategy for the authentication. Now need to test it.
Step 8 Run Application
Now need to run the application and test it working properly or not. Let’s run the application by the node app.js command;
Now check one by one all authentication. Now first check the authentication local. First signup that means register user locally:
It login successfully and go to the user profile page:
Now logout and login with correct email and else it give error. Like this:
If successfully login go to the user profile as like previous when register a new user. Now need to test all social authentication. First test the facebook:
It connect successfully with facebook and login in the facebook id it redirect to the profile page:
Now as like the facebook connect twitter and the google+ accounts.
Note: The config/authentication.js file will must keep client id and the secret key for which social media connect.
Now test unlink account which you may not link with the application .You unlink it:
Unlink with all accounts.
I hope that this article is very helpful for passport authentication with all types. Thanks!
Hưng Phi
Nice article!