Saturday, March 10, 2018

authentication using passpot.js in nodejs

Authentication using passportJs is the most popular and secure module. By using passportJs,  we can signin / login / authenticate very easily and quickly.

Here we will discuss regarding authentication locally with a simple plain password. Here we have use angularjs 1 but you can use any front-end html or  angularjs 2, angularjs 4,... or any other framework.

login.html

<div ng-controller="UserLoginController as ctrl">
            <h2>Login</h2>
            <form ng-submit="userLogin()" name="loginForm">
                  <input type="text" ng-model="user.email" name="email" placeholder="Enter your Email" required/>
                  <span ng-show="loginForm.$dirty && loginForm.email.$error.required">Please enter your email id.</span>
                  <span ng-show="loginForm.$dirty && loginForm.email.$invalid">Please enter correct email id</span>
                  <br/>
                  <input type="password" ng-model="user.password" name="password" placeholder="Enter password" required />
                  <span ng-show="loginForm.$dirty && loginForm.password.$error.required">Please enter your password</span>
                  <br/>
                  <br/>
                  <input type="submit" value="Submit" ng-disabled="loginForm.$invalid">
            </form>
      </div>

userAuthenticationCtrl.js

myapp.controller('UserLoginController', function($scope, $http, $location) {
      $scope.userLogin = function() {
          $http
          .post('/api/userLogin', user)
          .success(function(res) {
                        //saveToken(res.token);
                        console.log(res);
                        $location.path('/index');
                  })
                  .error(function(err) {
                        console.log('Error: ' + err);
                  });
      };
});

user.js (user model) // Stored in /app/model/user.js

'use strict';
/*
 *Declare variables and include mongoose
 */
var mongoose = require('mongoose'),
      Schema = mongoose.Schema,
      ObjectId = Schema.ObjectId;
var jwt = require('jsonwebtoken');

/*
 *Define structure of collection
 */
var userSchema = new Schema({
      social_id: { type: String },
      social_type: { type: String },
      user_name: { type: String },
      email: {
            type: String,
            index: true
      },
      password: String
      is_active: { type: String, enum: ['1', '0'], default: "1" },
      created_at: {
            type: Date,
            default: Date.now
      },
      updated_at: { type: Date },
}, { collection: 'user' });

/*
 *Validations
 */
userSchema.path('email').required(true, 'email is required!');
userSchema.path('email').match(/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/, 'fill a valid email address');

userSchema.path('email').validate(function(value, done) {
      this.model('User').count({ email: value }, function(err, count) {
            if (err)
                  return done(err);
            // If `count` is greater than zero, "invalidate"
            done(!count);
      });
}, 'Email already exists');

/*
 *methods
 */
userSchema.methods.generateJwt = function() {
      var expiry = new Date();
      expiry.setDate(expiry.getDate() + 7);

      return jwt.sign({
            _id: this._id,
            email: this.email,
            user_name: this.user_name,
            exp: parseInt(expiry.getTime() / 1000),
      }, "MY_SECRET", {
        expiresIn: '7d' //7 days
    }); // DO NOT KEEP YOUR SECRET IN THE CODE!
};

/*
 *Define model and export it for user in other page
 */
var User = mongoose.model('User', userSchema);
module.exports = User;

app.js

// set up ==============================
var express  = require('express');
var app      = express();
var mongoose = require('mongoose'); // mongoose for mongodb
var port       = process.env.PORT || 3000; // set the port

var morgan = require('morgan');  // log requests to the console (express4)
var bodyParser = require('body-parser'); // get information from HTML POST (express4)
var expressSession = require('express-session');
var cookieParser = require('cookie-parser'); // the session is stored in a cookie, so we use this to parse it
var methodOverride = require('method-override'); // simulate DELETE and PUT (express4)

//Using passport.js====================================
var passport = require('passport'); // for authenticate using passport.js
// [SH] Initialise Passport before using the route middleware
app.use(passport.initialize());
// must use cookieParser before expressSession
app.use(cookieParser());
app.use(expressSession({secret:'somesecrettokenhere',resave: true,saveUninitialized: true}));

// configuration ===============================================================  
var db = mongoose.connect('localhost', 'myapp', 27017);// load the database config

app.use(express.static(__dirname + '/public')); // set the static files location /public/img will be /img for users
app.use(morgan('dev')); // log every request to the console
app.use(bodyParser.urlencoded({'extended':'true'}));
app.use(bodyParser.json()); // parse application/json
app.use(bodyParser.json({ type: 'application/vnd.api+json' })); // parse application/vnd.api+json as json
app.use(methodOverride());
// routes ======================================================================

require('./app/routes.js')(app);

//Error handling ==================

// catch 404 and forward to error handler
app.use(function(req, res, next) {
    var err = new Error('Not Found');
    err.status = 404;
    next(err);
});

// error handlers

// [SH] Catch unauthorised errors
app.use(function (err, req, res, next) {
  if (err.name === 'UnauthorizedError') {
    res.status(401);
    res.json({"message" : err.name + ": " + err.message});
  }
});

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
    app.use(function(err, req, res, next) {
        res.status(err.status || 500);
        res.render('error', {
            message: err.message,
            error: err
        });
    });
}

// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
        message: err.message,
        error: {}
    });
});

// listen (start app with node server.js) ======================================
app.listen(port);
console.log("App listening on port " + port);


routes.js (for user authentication / login routing)

var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var mongoose = require('mongoose');
var User = require('./models/user');

module.exports = function(app) {
   
      app.post('/api/userLogin', function(req, res) {
            passport.authenticate('my-local', function(err, user, info) {
                  var token;
                  // If Passport throws/catches an error
                  if (err) {
                        res.status(404).json(err);
                        return;
                  }

                  // If a user is found
                  if (user) {
                        token = user.generateJwt();
                        res.status(200);
                        res.json({
                              "token": token
                        });
                  } else {
                        // If user is not found
                        res.status(401).json(info);
                  }
            })(req, res);
      });
   
     //Start =====================Passport authentication localStategy=============
      passport.use('user-local',new LocalStrategy({
                  usernameField: 'email',
                  passwordField: 'password'
            },
            function(username, password, done) {
                  User.findOne({ email: username }, function(err, user) {
                        if (err) {
                              return done(err);
                        }
                        // Return if user not found in database
                        if (!user) {
                              return done(null, false, {
                                    message: 'User not found'
                              });
                        }
                        // Return if password is wrong
                        if (!user.password === password) {
                              return done(null, false, {
                                    message: 'Password is wrong'
                              });
                        }
                        // If credentials are correct, return the user object
                        return done(null, user);
                  });
            }
      ));
      //End :=====================Passport authentication localStategy=============

      // application -------------------------------------------------------------
      app.get('*', function(req, res) {
            res.sendfile('./public/site/index.html'); // load the single view file (angular will handle the page changes on the front-end)
      });
};

From this way, we can authenticate by using passport js in nodejs.

For facebook authenticate using passportJs, review following link
https://laxmanchavda.blogspot.in/2018/03/facebook-authentication-using-passpotjs-in-nodejs.html

For twitter authenticate using passportJs, review following link
https://laxmanchavda.blogspot.in/2018/03/twitter-authentication-using-passportjs-in-nodejs.html

2 comments: