Authentication issue in Nodejs: ValidationError: Path `password` is required - passport.js

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' }

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

The way you did the passport authentication, it does not need to have the password required true in the user schema. Passport will automatically check the password if it's missing. If password is missing, passport will throw an error. So no need to make the password required true because passport will do the same job internally. This worked for me.
user.js
var userSchema=new mongoose.Schema({
username:{type:String,required:true},
email:{type:String,required:true},
password:String
});
server.js
app.post("/signUp",(req,res)=>{
User.register(new User({username:req.body.username,email:req.body.email}),req.body.password,(err,user)=>{
if(err){
console.log(err);
}else{
passport.authenticate("local")(req,res,()=>{
res.redirect("/");
});
}
});
});

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

You had this issue because you set the password field in your schema to
password: {type: String, required: true},
. You do not need that.
Use the info below and you will be fine.
password: {type: String}
See the working code below:
**user.js**
const mongoose = require('mongoose');
const passportLocalMongoose = require('passport-local-mongoose');
const userSchema = new mongoose.Schema({
username: {type: String, required: true},
password: {type: String} // no need to add required!
});
**server.js**
app.post('/register', (req, res) => {
const { username, password } = req.body;
User.register(new User({ username }), password, (err,user) => {
if (err) {
return res.render('register', { message: err.message, messageType:
'error', user: req.user });
}else{
passport.authenticate('local')(req, res, () => {
res.redirect('/dashboard');
});
}
});
});

Related

Status 201 on POST but Another Collection Created Instead of Using the Existing One [duplicate]

Am new in Nodejs, Am trying to create user login system with mongoDB and passportjs. Here i want to change collection name.
i refer this video here
This is my code:
Database connection js
config/database.js
module.exports = {
database : 'mongodb://localhost:27017/my_first_project',
secret : 'Mysecret'
}
models/admin.js
const mongoose = require('mongoose');
let AdminSchema = mongoose.Schema({
name:{
type: String,
required: true
},
email:{
type: String,
required: true
},
username:{
type: String,
required: true
},
password:{
type: String,
required: true
},
created_on:{
type: Date,
default: Date.now
},
status:{
type: Number,
required: true,
validate : {
validator : Number.isInteger,
message : '{VALUE} is not an integer value'
}
}
});
const Admin = module.exports = mongoose.model('User', AdminSchema);
config/passport.js
const LocalStorage = require('passport-local').Strategy;
const User = require('../models/admin');
const config = require('../config/database');
const bcrypt = require('bcryptjs');
module.exports = function(passport){
//Local Strategy
passport.use(new LocalStorage(function(username, password, done){
//Check username
let query = {username:username};
console.log(query);
User.findOne(query, function(err, user){
console.log(user);
if(err) throw err;
if(!user)
{
return done(null, false, {message: 'No user found'});
}
//check password
bcrypt.compare(password, user.password, function(err, isMatch){
if(err) throw err;
if(isMatch){
return done(null, user);
}else{
return done(null, false, {message: 'Wrong password'});
}
});
});
}));
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
}
This is my database structure
When i user correct username and password for login passportjs shows null.
Need to change collection name as admin.
I don't know how to ask this question. If am asking wrong sorry for all.
You can use this structure.
API structure of mongoose.model is this:
Mongoose#model(name, [schema], [collection], [skipInit])
which means
mongoose.model('User', AdminSchema, 'admin');
//Here 3rd argument 'admin': as collection name
You can do with this too
let AdminSchema = mongoose.Schema({
username : String,
password : String.
.......
}, { collection: 'admin' });
See this link from the Mongoose documentation.

Mongoose saves schema to different collection [duplicate]

Am new in Nodejs, Am trying to create user login system with mongoDB and passportjs. Here i want to change collection name.
i refer this video here
This is my code:
Database connection js
config/database.js
module.exports = {
database : 'mongodb://localhost:27017/my_first_project',
secret : 'Mysecret'
}
models/admin.js
const mongoose = require('mongoose');
let AdminSchema = mongoose.Schema({
name:{
type: String,
required: true
},
email:{
type: String,
required: true
},
username:{
type: String,
required: true
},
password:{
type: String,
required: true
},
created_on:{
type: Date,
default: Date.now
},
status:{
type: Number,
required: true,
validate : {
validator : Number.isInteger,
message : '{VALUE} is not an integer value'
}
}
});
const Admin = module.exports = mongoose.model('User', AdminSchema);
config/passport.js
const LocalStorage = require('passport-local').Strategy;
const User = require('../models/admin');
const config = require('../config/database');
const bcrypt = require('bcryptjs');
module.exports = function(passport){
//Local Strategy
passport.use(new LocalStorage(function(username, password, done){
//Check username
let query = {username:username};
console.log(query);
User.findOne(query, function(err, user){
console.log(user);
if(err) throw err;
if(!user)
{
return done(null, false, {message: 'No user found'});
}
//check password
bcrypt.compare(password, user.password, function(err, isMatch){
if(err) throw err;
if(isMatch){
return done(null, user);
}else{
return done(null, false, {message: 'Wrong password'});
}
});
});
}));
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
}
This is my database structure
When i user correct username and password for login passportjs shows null.
Need to change collection name as admin.
I don't know how to ask this question. If am asking wrong sorry for all.
You can use this structure.
API structure of mongoose.model is this:
Mongoose#model(name, [schema], [collection], [skipInit])
which means
mongoose.model('User', AdminSchema, 'admin');
//Here 3rd argument 'admin': as collection name
You can do with this too
let AdminSchema = mongoose.Schema({
username : String,
password : String.
.......
}, { collection: 'admin' });
See this link from the Mongoose documentation.

How to change collection name in mongoose.model?

Am new in Nodejs, Am trying to create user login system with mongoDB and passportjs. Here i want to change collection name.
i refer this video here
This is my code:
Database connection js
config/database.js
module.exports = {
database : 'mongodb://localhost:27017/my_first_project',
secret : 'Mysecret'
}
models/admin.js
const mongoose = require('mongoose');
let AdminSchema = mongoose.Schema({
name:{
type: String,
required: true
},
email:{
type: String,
required: true
},
username:{
type: String,
required: true
},
password:{
type: String,
required: true
},
created_on:{
type: Date,
default: Date.now
},
status:{
type: Number,
required: true,
validate : {
validator : Number.isInteger,
message : '{VALUE} is not an integer value'
}
}
});
const Admin = module.exports = mongoose.model('User', AdminSchema);
config/passport.js
const LocalStorage = require('passport-local').Strategy;
const User = require('../models/admin');
const config = require('../config/database');
const bcrypt = require('bcryptjs');
module.exports = function(passport){
//Local Strategy
passport.use(new LocalStorage(function(username, password, done){
//Check username
let query = {username:username};
console.log(query);
User.findOne(query, function(err, user){
console.log(user);
if(err) throw err;
if(!user)
{
return done(null, false, {message: 'No user found'});
}
//check password
bcrypt.compare(password, user.password, function(err, isMatch){
if(err) throw err;
if(isMatch){
return done(null, user);
}else{
return done(null, false, {message: 'Wrong password'});
}
});
});
}));
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
}
This is my database structure
When i user correct username and password for login passportjs shows null.
Need to change collection name as admin.
I don't know how to ask this question. If am asking wrong sorry for all.
You can use this structure.
API structure of mongoose.model is this:
Mongoose#model(name, [schema], [collection], [skipInit])
which means
mongoose.model('User', AdminSchema, 'admin');
//Here 3rd argument 'admin': as collection name
You can do with this too
let AdminSchema = mongoose.Schema({
username : String,
password : String.
.......
}, { collection: 'admin' });
See this link from the Mongoose documentation.

Unable to reference from token schema token mongodb express passport

i need help with this problem been dealing it for days.
i am trying to make a verification email route by using passport to hash passwords while issuing a verification token to the user.
here is my code for index.js in controllers folder
const User = require("../models/user");
const Token = require("../models/token")
const crypto = require("crypto");
const nodemailer = require("nodemailer");
var smtpTransport = nodemailer.createTransport({
service: 'Gmail',
auth: {
user: process.env.GMAILUSER,
pass: process.env.GMAILPW
}
});
module.exports = {
async postRegister(req, res, next) {
var user = new User({
name: req.body.name,
email: req.body.email,
isVerified: false,
username: req.body.username
});
await User.register(user, req.body.password);
res.redirect('/');
var token = new Token({ _userId: user._id, token: crypto.randomBytes(16).toString('hex') });
token.save(function (err) {
if (err) { return res.status(500).send({ msg: err.message
});
}
var mailOptions = {
to: user.email,
from: 'xxxt#xxx.com',
subject: 'xxxxx verify email',
text:'You are receiving this because you need to verify your email for your account.\n\n' +
'Please click on the following link, or paste this into your browser to complete the process:\n\n' +
'http://' + req.headers.host + '/confirmation/' + token.token + '\n\n' +
'If you did not request this, please ignore this email.\n'
};
smtpTransport.sendMail(mailOptions, function(err) {
if (err) { return res.status(500).send({ msg: err.message }); }
res.status(200).send('A verification email has been sent to ' + user.email + '.');
});
})
},
confirmationPost(req,res, next) {
Token.findOne({ token: req.params.token }, function (err, token) {
if (!token)
{console.log("sss")
} else {
User.findOne({ _id: token._userId, email: req.body.email }, function (err, user) {
if (!user) return console.log(user)
if (user.isVerified) return res.status(400).send({ type: 'already-verified', msg: 'This user has already been verified.' });
user.isVerified = true;
user.save(function (err) {
if (err) { return res.status(500).send({ msg: err.message }); }
res.status(200).send("The account has been verified. Please log in.");
})
});
};
})
}
}
This is my Token Schema
const mongoose = require('mongoose');
const passportLocalMongoose = require('passport-local-mongoose');
const Schema = mongoose.Schema;
const tokenSchema = new mongoose.Schema({
_userId: {
type: Schema.Types.ObjectId,
ref: 'User' },
token: {
type: String,
required: true },
createdAt: {
type: Date, required: true,
default: Date.now, expires: 43200 }
});
tokenSchema.plugin(passportLocalMongoose);
module.exports = mongoose.model('Token', tokenSchema);
lastly my user schema
const mongoose = require('mongoose');
const passportLocalMongoose = require('passport-local-mongoose');
const Schema = mongoose.Schema;
const UserSchema = new Schema({
username: String,
name: String,
email: { type: String, unique: true },
image: String,
isVerified: { type: Boolean, default: false },
password: String,
passwordResetToken: String,
passwordResetExpires: Date,
posts: [
{
type: Schema.Types.ObjectId,
ref: 'Post'
}
]
});
UserSchema.plugin(passportLocalMongoose);
module.exports = mongoose.model('User', UserSchema);
everything works fine until the part where the email verification was sent to my email and when i clicked on the link. It gives an error, i tried to console.log
and found that this line from controllers folder index.js
confirmationPost(req,res, next) {
Token.findOne({ token: req.params.token }, function (err, token) {
if (!token)
{console.log("err")
} else {
User.findOne({ _id: token._userId, email: req.body.email }, function (err, user) {
gives me back null.
how do i link that current line to get the token from the registered user?
i've used postman to send a get request to the confirmation route while giving it back the same token and it works.

NodeJS + Mongoose , 'unique' field attribute not working?

I am making sure that my db doesnt have duplicate usernames or email addresses for my users using the unique: true attribute, but I am able to create users with duplicate usernames...so something isn't working. I have tried dropping the database, this did not solve the issue. Also in Model.on('index'), sometimes the error is not outputted to the console, sometimes it is. Strange.
var userSchema = mongoose.Schema({
username: {type: String, unique: true, required: true},
password: {type: String, required: true, select: false},
emailAddress: {type: String, unique: true, required: true},
emailVerified: {type: Boolean, default: false},
emailVerificationCode: {type: Number},
friends: []
});
userSchema.pre('save', function(next) {
var user = this;
if (!user.isModified('password')) return next();
bcrypt.genSalt(10, function(err, salt) {
if (err) return next(err);
bcrypt.hash(user.password, salt, function(err, hash) {
if (err) return next(err);
user.password = hash;
next();
});
});
});
var User = mongoose.model('User', userSchema);
User.on('index', function(err) {
console.log(err);
});
module.exports = User;
And my node router for adding users to the db...
router.post('/register', function(req, res, next) {
var newUser = new User({ username: req.body.username, password: req.body.password, emailAddress: req.body.email });
newUser.save(function(err, newUser) {
if (err) return next(err);
newUser.sendVerificationEmail(function(err, isSent) {
if (err) return next(err);
res.json({ success: true });
});
});
});

Resources