What's the proper way to validate old user password while updating new password?
So far i have tried and always get error: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
What i did:
I tried using bcrypt to compare the old password from req.body with user existing password and then hash with bcrypt before saving. Comparing the password using bcrypt gave the error above. Not comparing the old password at all and just saving new password works properly.
My code:
exports.updatePassword = async (req, res) => {
try {
const { oldPassword, password } = req.body;
let updatedPassword = {
password: password,
};
const user = await User.findOneAndUpdate(
{ _id: req.params.userId },
{ $set: updatedPassword },
{ new: true, useFindAndModify: false }
);
// validate old password
bcrypt.compare(oldPassword, user.password, function (err, match) {
if (!match || err)
return res.status(400).send('Please enter correct old password');
});
//hash password and save user
bcrypt.genSalt(12, function (err, salt) {
bcrypt.hash(user.password, salt, (err, hash) => {
user.password = hash;
user.save();
return res.json({user});
});
});
} catch (err) {
console.log(err);
return res.status(400).send('Something went wrong. Try again');
}
};
The issue is that the updatePassword function is ending before you actually process everything. To avoid nested function calls and returns, use the async methods provided by bcrypt (also check their recomendation on using async vs sync).
Regarding the code itself, you are updating the user's password before checking if the password is valid. You should get the user from the db, check if the current password matches, and only then insert the new hashed password into the db.
exports.updatePassword = async (req, res) => {
const { oldPassword, password } = req.body;
try {
// get user
const user = await User.findById(req.params.userId);
if (!user) {
return res.status(400).send('User not found');
}
// validate old password
const isValidPassword = await bcrypt.compare(oldPassword, user.password);
if (!isValidPassword) {
return res.status(400).send('Please enter correct old password');
}
// hash new password
const hashedPassword = await bcrypt.hash(password, 12);
// update user's password
user.password = hashedPassword;
const updatedUser = await user.save();
return res.json({ user: updatedUser });
} catch (err) {
console.log(err);
return res.status(500).send('Something went wrong. Try again');
}
};
This is my login code. Unhandledpromises occour while comparing Users input password and stored password.
exports.login = (req, res) => {
try {
const {email, password} = req.body
console.log(req.body)
if(!email || !password) {
return res.status(400).render('login', {
message: 'Please Provide an email and password'
})
}
db.query('SELECT * FROM users WHERE email = ? ',{email}, async (error, results) => {
console.log(error)
console.log(results)
if( !results || !(await bcrypt.compare(password, results[0].password)) ) {
res.status(401).render('login', {
message: 'Email or Password is Incorrect'
})
}
})
} catch (error) {
console.log(error)
}
}
Console.log(error) is null..
Updated
I'd suggest you to promisify db.query so you can await it, the errors will then be properly caught in the catch block, and your code will be flattened.
Your error is caused by results[0] which is undefined when trying to access its password property, which means that results is an empty array.
The second argument of query should not be an Object but an Array, so replace { email } with [email]:
const {
promisify
} = require('util');
const query = promisify(db.query.bind(db));
exports.login = async (req, res) => {
try {
const {
email,
password
} = req.body;
if (!email || !password) {
return res.status(400).render('login', {
message: 'Please Provide an email and password'
});
}
const results = await query('SELECT * FROM users WHERE email = ? ', [email]); // problem occur due to usage of curly brackets.
if (!results || !(await bcrypt.compare(password, results[0].password))) {
res.status(401).render('login', {
message: 'Email or Password is Incorrect'
});
}
} catch (error) {
console.log(error);
}
}
Novice in my programming endeavors, but I am stuck and cannot find any help. I am able to register users into my db and hash the password. I am trying to be able to login with that user. I am able to check for required field in email and password, but when I enter a user in the db with the correct password the page hangs.
'''
exports.login = (req,res) =>{
try {
const {email, password} = req.body;
if (!email || !password){
return res.status(400).render('login', {
message: 'Email and password required.'
})
}
db.query ('SELECT * FROM users WHERE email = ?', [email], async (error, results)=> {
if(error)
console.log(error)
if(!results){
res.status(401).render('login', {
message: 'Invalid email or password.'
})
}else{
await bcrypt.compare(req.body.password, results.password)
if(bool == false){
res.status(401).render('login', {
message: 'Invalid password.'
})
}else{
res.status(401).render('index', {
message: 'User Logged in'
});
}
}
})
} catch (error) {
console.log(error);
}
}'''
Try this function : (bcryptCompare.js)
const checkBcrypt = async function(pass, hash) {
const bcrypt = require('bcrypt');
return new Promise(resolve => {
bcrypt.compare(pass, hash, function(bcryptErr, bcryptRes) {
if (bcryptErr) {
console.log('ERROR -> BCRYPT');
return resolve(false);
} else {
if (!bcryptRes) {
return resolve(false);
} else {
return resolve(true);
}
}
});
});
}
module.exports = checkBcrypt;
You can use it like this:
const checkBcrypt = require('./bcryptCompare');
const checkPass = await checkBcrypt(req.body.password, results.password);
if(checkPass){
//
} else {
//invalid password
}
I have a POST route that takes an username and password and returns a token on successful login. If either username or password are blank, it returns an error. However, if I provide a wrong username or password, I'm still getting a token generated from the provided information. How can I check the information returned from the database to return the same wrong username or password error? This is my route:
router.post('/login', (req, res) => {
if (req.body.username == '' || req.body.password == '') {
res.status(401).send({ error: "Wrong username or password" });
} else {
queries.login(req.body.username, req.body.password).then((user) => {
if (res.error) {
res.status(401).send({ error: 'Wrong username or password' });
}
res.json(auth.getToken(user.id, user.username));
});
}
});
And this is my query:
async login(username, password) {
let getUser = await knex('users').where('username', username);
let user = getUser[0];
try {
if (await argon.verify(user.password_hash, password)) {
return user;
}
} catch (e) {
return e;
}
}
In your login query you need to throw an error for the error case, like:
async login(username, password) {
try {
let getUser = await knex('users').where('username', username);
let user = getUser[0];
if (await argon.verify(user.password_hash, password)) {
return user;
}
throw Error('User not verified');
} catch (e) {
throw Error(e.message);
}
}
Then in your route you can handle the error case by using .catch():
router.post('/login', (req, res) => {
if (req.body.username == '' || req.body.password == '') {
res.status(401).send({ error: "Wrong username or password" });
} else {
queries.login(req.body.username, req.body.password)
.then((user) => {
res.json(auth.getToken(user.id, user.username));
});
.catch((error) => {
res.status(401).send({ error: 'Wrong username or password' });
});
}
});
I'm trying to build logging application in node JS. in here password authentication app do not work properly. when i enter username and password it occur following error and stop server.
this is the error.
Here is the code for authentication part
passport.use(new LocalStrategy(
function(username, password, done) {
User.getUserByUsername(username, function(err, user){
if(err) throw err;
if (!user) {
return done(null, false, {message: 'Unknown user'});
}
User.comparePassword(password, user.password, function(err, isMatch){
if(err) throw err;
if (isMatch) {
return done(null, user);
} else {
return done(null, false, {message: 'Invalid password'});
}
});
});
}));
This code work for Unknown user.
but it is not working for comparing username and password. i cannot see any bug in here. i want a help for solve this.
In the name of the universe programmer
in my case i forgot to select the password
because in database the password was ((select: false))
this code for app
const user = await User.findOne({email}).select("+password")
i forgot to append the ((.select("+password")))to the findOne
and I received this error ;
Error: Illegal arguments: string, undefined
and this code for database
const User = new mongoose.Schema({
username:{
type:String,
required: [true,"نام کاربری ضروری است"]
},
email:{
type:String,
required: [true,"رایانامه ضروری است"],
unique: true,
match:[
/^\w+([\.-]?\w+)*#\w+([\.-]?\w+)*(\.\w{1,3})$/,
"لطفا یک رایانامه صحیح وارد کنید"
]
},
password:{
type:String,
required:[true,"رمز ضروری است"],
minlegth: 5,
select: false
}
})
I found the problem in here. it is not things regarding the code.
The thing is i had registered two users with same user name and different password. then when i tried to login with the user name and one password it occurred this error and stop the server.
Because there is embarrassing situation with find password to username that user entered. because there are two password with same username.
In my case, I was using arrow function
userSchema.methods.comparePassword = async (enterdPassword) => {
return await bcrypt.compare(enterdPassword, this.password);
};
which I converted to normal function
userSchema.methods.comparePassword = async function (enterdPassword) {
return await bcrypt.compare(enterdPassword, this.password);
};
that solved the problem
In my case, I'm using social signin/signup. When the user is signing up using a social login option, the value of the password stored is "NULL".
So I just added this little check :
comparePassword: function(password, user){
if (!user.password)
return false;
return bcrypt.compareSync(password, user.password);
}
At
"models/user.js"
Inside comparePassword
module.exports.comparePassword = (candidatePassword, hash, callback) => {...)
Add this code:
bcrypt.hash(candidatePassword, 10, (err, hash) => {
if(err) {
throw err;
}
bcrypt.compare(candidatePassword, hash, (err, isMatch) => {
if(err) {
throw err;
}
callback(null, isMatch);
});
});
Here We are grabbing username and password from the sign in page AND
finding our user by the username from the database and then
Matching its encrypted password with an entered password by the user
passport.use(new LocalStrategy(
(username,password,done)=> {
db.users.findOne({username: username},(err, user)=> {
if(err) return done(err);
if(!user) {
return done(null,false,{message: 'Incorrect Username'});
}
bcrypt.compare(password, user.password,(err,isMatch)=> {
if(err) return done(err);
if(isMatch) {
return done(null, user);
} else {
return done(null, false,{message: 'Incorrect Password'});
}
});
});
}
));
You need to apply await to your salt and password assignments too.
Like this,
const salt = await bcrypt.genSaltSync(10);
const password = await req.body.password;
You can write a code like this: After this.findOne({ select: [] ........}) ... I hope this is helpful
async validateUserPassword(loginDto: AuthLoginDto): Promise<User> {
const { mobile, email, password } = loginDto;
const user = await this.findOne({
select: ['id', 'email', 'mobile', 'password', 'salt', 'status', 'logged_at'],
where: [
{ mobile: mobile },
{ email: email }
]
});
if (user && await user.validatePassword(password)) {
const logged_at = {
logged_at: new Date()
}
await this.update({ id: user.id }, logged_at)
return user;
} else {
return null;
}
}
async validatePassword(password: string): Promise<boolean> {
const hash = await bcrypt.hash(password, this.salt);
return hash === this.password;
}
In my own case , I just want to check if the old password matches the password in Db but got the error , here is my code below:
changePassword = asyncHandler (async (req: IGetUserAuthInfoRequest, res: Response) => {
const user = await User.findById(req.user._id)
const {oldPassword, password} = req.body
if(!user) {
res.status(400)
throw new Error("User not found, please signup")
}
// Validate
if(!oldPassword || !password) {
res.status(400)
throw new Error("Please add old and new password")
}
// Check if old password matches password in DB
const passwordIsCorrect = await bcrypt.compare(oldPassword, user.password)
// Save new password
if(user && passwordIsCorrect) {
user.password = password
await user.save()
res.status(200).send("Password change successful")
} else {
res.status(400)
throw new Error("Old password is incorrect")
}
});