Node.js and Passport Object has no method validPassword

13,950

Solution 1

You are using

if (!user.validPassword(password)) {
    return done(null, false, { message: 'Incorrect password.' });
}

but you haven't defined validPassword method. Attach it to your schema:

var authSchema = mongoose.Schema({ 
    username: 'string',
    password: 'string'
});
authSchema.methods.validPassword = function( pwd ) {
    // EXAMPLE CODE!
    return ( this.password === pwd );
};

EDIT You've also incorrectly defined the schema. It should be:

var authSchema = mongoose.Schema({ 
    username: String,
    password: String
});

Note that both username and password should be String type objects, not strings "string", if you know what I mean. :)

Solution 2

Looks like you copied example from passportjs website, where Jared failed to mention how to implement it..

On the passport js github page he has another (simpler) example; he removed validPassword method altogether (line 18):

Example

if (user.password != password) { return cb(null, false); }

That's what I based my app on (using encryption) on top of it.

Solution 3

Also being a noob at this, it took me a whole day to figure this one out. I used the history from another one of Jared's example apps and some crypto advice from folks on here.

First off I made a method that generates a salt (a big random number which is stringified), uses the salt and the user's password to create a hash (with the help of the nodejs 'crypto' module), and finally stores both the salt and the hash every time before mongoose saves a new account.

//make hash
userSchema.pre('save', function(next) {
    var user = this;
    if(!user.isModified('password')) return next();
    var rand = (Math.floor(Math.random() * 1000000000)).toString(36);
    var hash = crypto.createHash('md5').update(user.password + rand).digest("hex");
    user.password = hash;
    user.salt = rand;
    next();
});

For the verification I simply take the inputted password (at login) and attempt the make the same hash again using the salt. I then compare the stored hash to the new one and return true or false accordingly.

 // Password verification
    userSchema.methods.validPassword = function(password) {
      var testhash = crypto.createHash('md5').update(password + this.salt).digest("hex");
      if(testhash === this.password) {
        return true;
      } else {
        return false;
      }
    }
Share:
13,950

Related videos on Youtube

Muhammad Saleh
Author by

Muhammad Saleh

Egyptian UI Developer - works for Vodafone Egypt

Updated on September 14, 2022

Comments

  • Muhammad Saleh
    Muhammad Saleh over 1 year

    I'm using Node.js + Express + Passport to create a simple authentication(local)

    and what I've reached so far that when a wrong username or password entered user is redirected to an error page

    but when the user enters a correct username and password I get this error

    node_modules\mongoose\lib\utils.js:435
        throw err;
              ^
    TypeError: Object { _id: 50b347decfd61ab9e9e6768f,
    username: 'saleh',
    password: '123456' } has no method 'validPassword'
    

    I'm not sure what's wrong there

    app.js (I removed the unnecessary code):

      var passport = require('passport')
      , LocalStrategy = require('passport-local').Strategy;
    
      app.configure(function(){
      app.set('port', process.env.PORT || 3000);
      app.set('views', __dirname + '/views');
      app.set('view engine', 'ejs');
      app.use(express.favicon());
      app.use(express.logger('dev'));
      app.use(express.bodyParser());
      app.use(express.methodOverride());
      app.use(passport.initialize());
      app.use(passport.session());
      app.use(app.router);
      app.use(express.static(path.join(__dirname, 'public')));
    });
    
    
    
    var mongoose = require('mongoose');
    var db = mongoose.createConnection('localhost', 'authTest');
    
    var authSchema = mongoose.Schema({ 
      username: 'string',
      password: 'string'
    });
    
    var User = db.model('users', authSchema);
    
    
    passport.use(new LocalStrategy(
      function(username, password, done) {
        User.findOne({ username: username }, function (err, user) {
          if (err) { return done(err); }
          if (!user) {
            return done(null, false, { message: 'Incorrect username.' });
          }
          if (!user.validPassword(password)) {
            return done(null, false, { message: 'Incorrect password.' });
          }
          return done(null, user);
        });
      }
    ));
    
    
    
    passport.serializeUser(function(user, done) {
      done(null, user.id);
    });
    
    passport.deserializeUser(function(id, done) {
      User.findById(id, function(err, user) {
        done(err, user);
      });
    });
    
    
    
    
    app.post('/login',
      passport.authenticate('local', { successRedirect: '/',
                                       failureRedirect: '/login/error',
    
                                      })
    );
    

    and now in routes/login.js

    var mongoose = require('mongoose');
    var db = mongoose.createConnection('localhost', 'authTest');
    
    var authSchema = mongoose.Schema({ 
        username: 'string',
        password: 'string'
    });
    
    var User = db.model('users', authSchema);
    
    exports.index = function(req, res){
    User.find(function (err, list) {
            res.render('login', { title: 'Usernames and Passwords', users: list,msg:""});
        });
    };
    

    Thanks for your time.

  • Muhammad Saleh
    Muhammad Saleh over 11 years
    Thanks I really needed a simpler example and I've also contacted Jared to make a better documentation :)
  • Muhammad Saleh
    Muhammad Saleh over 11 years
    Another question if you may.. can you recommend me a book or any resource to learn Node.js better ?
  • freakish
    freakish over 11 years
    @MuhammadSaleh I don't know any Node.JS book. I've learned everything by constantly googling. Start with tutorial on Node.JS main page. And then just google. Stackoverflow is a great source of knowledge as well. That's how I've learned it.
  • Rorschach120
    Rorschach120 over 10 years
    That moment when you realize this is a year old.
  • Muhammad Saleh
    Muhammad Saleh over 10 years
    It's okay :) Thanks for the contribution
  • IIllIIll
    IIllIIll almost 8 years
    This is for Passport, though. Shouldn't there already be functionality for hashing passwords and checking them?
  • David Sherret
    David Sherret over 3 years
    This answer should probably be updated because using md5 and Math.random is not secure.