Node.js and Passport Object has no method validPassword
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):
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;
}
}
Related videos on Youtube
Muhammad Saleh
Egyptian UI Developer - works for Vodafone Egypt
Updated on September 14, 2022Comments
-
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 over 11 yearsThanks I really needed a simpler example and I've also contacted Jared to make a better documentation :)
-
Muhammad Saleh over 11 yearsAnother question if you may.. can you recommend me a book or any resource to learn Node.js better ?
-
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 over 10 yearsThat moment when you realize this is a year old.
-
Muhammad Saleh over 10 yearsIt's okay :) Thanks for the contribution
-
IIllIIll almost 8 yearsThis is for Passport, though. Shouldn't there already be functionality for hashing passwords and checking them?
-
David Sherret over 3 yearsThis answer should probably be updated because using md5 and
Math.random
is not secure.