Home > DeveloperSection > Articles > User Authentication with All Social Account under One Account in Node.js

User Authentication with All Social Account under One Account in Node.js


Node.JS Google API  Facebook API  Twitter API  Node JS 
Ratings:
3 Comment(s)
 5072  View(s)
Rate this:

User Authentication with All Social Account under One Account in Node.js

 

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

                                }));

 

------------Facebook

                                // 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 : '/'

                                                }));

------------twitter

                                // 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

                                }));

 

------------Facebook

 

                                // 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 : '/'

                                                }));

 

---------------twitter

 

                                // 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 : '/'

                                                }));

 

 

----------------google

 

                                // 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!

 


Hung Nguyen

By Hưng Phi on   one year ago
Nice article! 

Brill

By Sharry Stowell on   one year ago
Thanks for posting :)

Excellent article!

By Keith Garsson on   one year ago
Was even able to adapt it to my existing Mongo schema as I followed along.Very clear and well-structured



Don't want to miss updates? Please click the below button!

Follow MindStick