passport.jspassport-local

Authentication issue in Nodejs: ValidationError: Path `password` is required


I am getting an error ValidationError: Path password is required, when trying to register a new User. I am new to Node, programming, and authentication.

Here is the code I have, and then I will walk through what I have done to try to trouble shoot it.

User model and schema

var mongoose = require("mongoose");
var passportLocalMongoose = require("passport-local-mongoose");
var bcrypt = require("bcrypt-nodejs");

var UserSchema = new mongoose.Schema({
    username: {type: String, unique: true, required: true},
    password: {type: String, unique: true, required: true},
    // avatar: String,
    firstName: String,
    lastName: String,
    email: {type: String, unique: true, required: true},
    resetPasswordToken: String,
     resetPasswordExpires: Date,
    // isAdmin: {type: Boolean, default: false}
});

UserSchema.plugin(passportLocalMongoose);

//save function -- hashes and then saves the password
UserSchema.pre('save', function(next) {
  var user = this;
  var SALT_FACTOR = 5;

  if (!user.isModified('password')) return next();

  bcrypt.genSalt(SALT_FACTOR, function(err, salt) {
    if (err) return next(err);

    bcrypt.hash(user.password, salt, null, function(err, hash) {
      if (err) return next(err);
      user.password = hash;
      next();
    });
  });
});

//compares and checks password

UserSchema.methods.comparePassword = function(candidatePassword, cb) {
  bcrypt.compare(candidatePassword, this.password, function(err, isMatch) {
    if (err) return cb(err);
    cb(null, isMatch);
  });
};

module.exports = mongoose.model("User", UserSchema);

Here is my app.js file:

var express = require("express"),
    app = express(),
    bodyParser = require("body-parser"),
    mongoose = require("mongoose"),
    expressSanitizer = require("express-sanitizer"),
    passport = require("passport"),
    cookieParser = require("cookie-parser"),
    LocalStrategy = require("passport-local"),
    session = require("express-session"),
    nodemailer = require("nodemailer"),
    bcrypt = require("bcrypt-nodejs"),
    async = require("async"),
    crypto = require("crypto"),
    flash = require("connect-flash"),
    moment = require("moment"),
    User = require("./models/user"),
    // seedDB      = require("./seeds"),
    methodOverride = require("method-override");


// APP CONFIG
mongoose.connect("mongodb://localhost/blog", {useMongoClient: true});
//PRODUCTION CONFIG - LIVE URL GOES HERE!

app.set("view engine", "ejs");
app.use(express.static(__dirname + "/assets"));
app.use(bodyParser.urlencoded({extended: true}));
app.use(expressSanitizer());
app.use(methodOverride("_method"));
app.use(cookieParser('secret'));
//require moment
app.locals.moment = require('moment');
// seedDB(); //seed test data!


// PASSPORT CONFIGURATION
app.use(require("express-session")({
    secret: "It's a secret to everyone!!",
    resave: false,
    saveUninitialized: false
}));

app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
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.' });
    console.log(user);
    User.comparePassword(password, function(err, isMatch) {
      if (isMatch) {
        return done(null, user);
      } else {
        return done(null, false, { message: 'Incorrect password.' });
      }
    });
  });
}));
passport.serializeUser(function(user, done) {
  done(null, user.id);
});

passport.deserializeUser(function(id, done) {
  User.findById(id, function(err, user) {
    done(err, user);
  });
});

app.use(function(req, res, next){
   res.locals.currentUser = req.user;
   res.locals.success = req.flash('success');
   res.locals.error = req.flash('error');
   next();
});


// REQUIRE ROUTES
var commentRoutes = require("./routes/comments"),
    bpostRoutes = require("./routes/bposts"),
    indexRoutes = require("./routes/index");


//USE ROUTES
app.use("/", indexRoutes);
app.use("/bposts", bpostRoutes);
app.use("/bposts/:id/comments", commentRoutes);


//RUN SERVER
app.listen(process.env.PORT, process.env.IP, function(){
   console.log("The Server Has Started!");
});

Here is the index.js route file for posting new Users

// handle sign up logic

router.post("/register", function(req, res) {

    var newUser = new User({
        username: req.sanitize(req.body.username),
        firstName:req.sanitize(req.body.firstName),
        lastName: req.sanitize(req.body.lastName),
        email: req.sanitize(req.body.email),
    });
   console.log(newUser);

    // if (req.body.adminCode === 'secretcode123') {
    //     newUser.isAdmin = true;
    // }

    User.register(newUser, req.body.password, function(err, user) {
        if (err) {
            console.log(err);
            return res.render("register", { error: err.message });
        }
        passport.authenticate("local")(req, res, function() {
            req.flash("success", "Successfully Signed Up! Nice to meet you " + req.body.username);
            res.redirect("/bposts");
        });
    });
});

As you can see in the index.js

I did a console.log(newUser) and it brings back the entire newUser object.

{ username: 'apple',
      firstName: 'apple',
      lastName: 'apple',
      email: 'apple@gmail.com',
      _id: 5a2eac41720dc60acffa02f4 }

Outside of this I am not sure what other testing I could do to locate whats happening behind the scenes. Any help or pointers on how to think about this kind of problem in the future so I can resolve it myself would be awesome. Thanks.

Here is the full StackTrace as well if it helps:

  { ValidationError: User validation failed: password: Path `password` is required.
    at MongooseError.ValidationError.inspect (/home/ubuntu/workspace/node_modules/mongoose/lib/error/validation.js:57:23)
    at formatValue (util.js:351:36)
    at inspect (util.js:185:10)
    at exports.format (util.js:71:24)
    at Console.log (console.js:43:37)
    at /home/ubuntu/workspace/routes/index.js:35:21
    at /home/ubuntu/workspace/node_modules/passport-local-mongoose/index.js:213:33
    at /home/ubuntu/workspace/node_modules/mongoose/lib/model.js:4038:16
    at /home/ubuntu/workspace/node_modules/mongoose/lib/services/model/applyHooks.js:175:17
    at _combinedTickCallback (internal/process/next_tick.js:73:7)
    at process._tickCallback (internal/process/next_tick.js:104:9)
  errors: 
   { password: 
      { ValidatorError: Path `password` is required.
          at MongooseError.ValidatorError (/home/ubuntu/workspace/node_modules/mongoose/lib/error/validator.js:25:11)
          at validate (/home/ubuntu/workspace/node_modules/mongoose/lib/schematype.js:782:13)
          at /home/ubuntu/workspace/node_modules/mongoose/lib/schematype.js:829:11
          at Array.forEach (native)
          at SchemaString.SchemaType.doValidate (/home/ubuntu/workspace/node_modules/mongoose/lib/schematype.js:789:19)
          at /home/ubuntu/workspace/node_modules/mongoose/lib/document.js:1528:9
          at _combinedTickCallback (internal/process/next_tick.js:73:7)
          at process._tickCallback (internal/process/next_tick.js:104:9)
        message: 'Path `password` is required.',
        name: 'ValidatorError',
        properties: [Object],
        kind: 'required',
        path: 'password',
        value: undefined,
        reason: undefined,
        '$isValidatorError': true } },
  _message: 'User validation failed',
  name: 'ValidationError' }

Solution

  • Basically you defined that you need a password in your models.

    var UserSchema = new mongoose.Schema({
        username: {type: String, unique: true, required: true},
        password: {type: String, unique: true, required: true}, // <-- See here
        firstName: String,
        lastName: String,
        email: {type: String, unique: true, required: true},
        resetPasswordToken: String,
        resetPasswordExpires: Date
    });
    

    But when you are saving you aren't passing it a password:

    var newUser = new User({
        username: req.sanitize(req.body.username),
        firstName:req.sanitize(req.body.firstName),
        lastName: req.sanitize(req.body.lastName),
        email: req.sanitize(req.body.email),
        /* password: req.sanitize(req.body.password) // <- Probably missing something like this.*/
    });
    

    I didn't write the following blog, but I think it might be helpful for you.

    https://github.com/DDCreationStudios/Writing/blob/master/articles/AuthenticationIntro.md#user-registration