Passport: Allow sign up with name and email address? (Local Strategy)

Forivin picture Forivin · Sep 4, 2015 · Viewed 15.2k times · Source

Is there any way to allow a user to register on the local strategy with his password, email and name?
Every example I could find online only use name/password or email/password.

I also searched through the the whole passport documentation, but that documentation isn't helpful at all. It's just one bloated site full of examples.
I just need an list of functions, classes and variables passport uses with explanations what they and every parameter of them do. Every good library has something like that, why can't I find it for passport?

Here are the key parts of my code:

passport.use('local-signup', new LocalStrategy({
    usernameField: 'email',
    passwordField: 'password',
    //are there other options?
    //emailField did not seem to do anything
    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) {
    //check if email not already in database
        //create new user using "email" and "password"
        //I want an additional parameter here "name"
}));

So is passport really that limited? There has to be a way to do this, right?

Answer

Eugene Obrezkov picture Eugene Obrezkov · Sep 13, 2015

You can be a little confused but passport doesn't implement signup methods. It's just authorisation library. So you must handle that use-case on your own.

First of all, create route that will be responsible for sign-up and your checks:

signup: function (req, res) {
  User
    .findOne({
      or: [{username: req.param('username')}, {email: req.param('email')}]
    })
    .then(function(user) {
      if (user) return {message: 'User already exists'};          
      return User.create(req.allParams());
    })
    .then(res.ok)
    .catch(res.negotiate);
}

The example above is based on Sails framework, but you can fit it with no problems to your own case.

Next step is include passport local strategy.

var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;

var LOCAL_STRATEGY_CONFIG = {
  usernameField: 'email',
  passwordField: 'password',
  session: false,
  passReqToCallback: true
};

function _onLocalStrategyAuth(req, email, password, next) {
  User
    .findOne(or: [{email: email}, {username: email}])
    .then(function (user) {
      if (!user) return next(null, null, {
        code: 'E_USER_NOT_FOUND',
        message: email + ' is not found',
        status: 401
      });

      if (!HashService.bcrypt.compareSync(password, user.password)) return next(null, null, {
        code: 'E_WRONG_PASSWORD',
        message: 'Password is wrong',
        status: 401
      });

      return next(null, user, {});
    })
    .catch(next);
}

passport.use(new LocalStrategy(LOCAL_STRATEGY_CONFIG), _onLocalStrategyAuth));

We have only signin task now. It's simple.

signin: function(req, res) {
  passport.authenticate('local', function(error, user, info) {
    if (error || !user) return res.negotiate(Object.assign(error, info));
    return res.ok(user);
  })(req, res);
}

This way is more suitable for passport and works great for me.