bcrypt.compare always returns false - node.js

I am trying to get a login function going but when I try to compare password with hashed password it always returns false
This is my registerUser function that holds the hashing
const registerUser = async (request, response) => {
const hashedPassword = await bcrypt.hash(request.body.password, 12)
const user = new UserModel({
username: request.body.username,
password: hashedPassword
});
try {
const databaseResponse = await user.save();
response.status(201).send(databaseResponse);
} catch (error) {
response.status(500).send({message: error.message});
}
};
This is the login function that holds the compare
const login = async (request, response) => {
try{
const user = await UserModel.findOne({username: request.body.username})
if(!user) return response.status(403).send('no user with name ' + request.body.username + ' found');
const isPassValidated = await bcrypt.compare(request.body.password, user.password)
if(!isPassValidated) return response.status(403).send('wrong password');
response.status(200).send('yay');
} catch(error){
response.status(500).send({message: error.message});
}
}
When I console.log request.body.password and user.password the hashed string is equal to the unhashed string so it should return true
The hashed string is the same string that is saved in the database

I just found the issue, thank you for your help. in userSchema, password was lowercase:true which caused the issue...

The code looks alright. Do you have multiple users with the same username in your database? The generated hash should be: $2b$12$jgrLYOqnHnJGszlpgo26QuaT29tdxBFguyIttSNOIy/8go1viRrYC

Related

Having trouble getting a POST request to work

I'm using Node, Express, & Mongoose trying to get this POST request to work using Postman but it keeps giving me the 500 status error. I also tried posting with just the username & instead of giving me the expected 400 status error it just gave me a 500 error again.
const jwt = require('jsonwebtoken')
const bcrypt = require('bcrypt')
const User = require('../models/userModel');
const registerUser = async (req, res) => {
try {
//get the username & password from the req.body
const { username, password } = req.body;
//check if the username is unique
const uniqueCheck = await User.findOne(username);
if (uniqueCheck) {
res.status(403).json('Username already exists');
}
//hash password
const salt = await bcrypt.genSalt(10);
const hash = await bcrypt.hash(password, salt);
//check all fields are filled
if (!username || !password) {
res.status(400).json('Please fill in all fields')
} else {
//create user with username & password that is assigned to the hash version of it
const user = await User.create(username, { password: hash });
res.status(201).json(user);
}
} catch (error) {
res.status(500).json({ error: 'Problem registering user' });
}
}
As already I told you in the comment, you should ad a console.error statement in the catch block to better understand where is the problem.
Also, if the first if is matched, a response is sent to the client but the code execution will countinue, triyng to repliyng again to the client and giving you another error. You should return in the first if block to avoid it.
Check the following solution with comments on relevant edits
const jwt = require('jsonwebtoken')
const bcrypt = require('bcrypt')
const User = require('../models/userModel');
const registerUser = async (req, res) => {
try {
//get the username & password from the req.body
const { username, password } = req.body;
//check if the username is unique
const uniqueCheck = await User.findOne(username);
if (uniqueCheck) {
return res.status(403).json('Username already exists'); // --> !!! add a return statement here
}
//hash password
const salt = await bcrypt.genSalt(10);
const hash = await bcrypt.hash(password, salt);
//check all fields are filled
if (!username || !password) {
res.status(400).json('Please fill in all fields')
} else {
//create user with username & password that is assigned to the hash version of it
const user = await User.create(username, { password: hash });
res.status(201).json(user);
}
} catch (error) {
console.error(error) // --> !!! log errors here
res.status(500).json({ error: 'Problem registering user' });
}
}

Bcrypt compare method is not returning true when hash password is stored in the database

userSchema.statics.findByCredentials = async (email, password) => {
const user = await User.findOne({ email })
if (!user) {
throw new Error('no user found!')
}
const isMatch = await bcrypt.compare(password, user.password)
if (!isMatch) {
throw new Error('invalid credentials!')
}
return user
}
The above code is matching the hash password that is stored in the database with a plain text password but it always returns false.
so I tried this & it's working, could anyone explain to me; why this code is working & the above one is not working?
const bcrypt = require('bcryptjs')
const encription = async () => {
const password = 'abc1234';
console.log('plain password: ', password);
const hashPass = await bcrypt.hash(password, 8);
console.log(`hash password: ${hashPass}`);
const isValidPass = await bcrypt.compare(password, hashPass);
console.log(`is valid: ${isValidPass}`);
}
encription();

await bcrypt.compare(req.body.password, user.password) return false

The bcrypt.compare returns false always when it compares the result from the DB with the string password.
Hi Dear, I am trying to create a login authentication for my form. I create the user with a hash password and then I am trying to log in but during to compare plain text password and hashed password bcrypt.compare return false.
When I create a hash password and compare it in the same function it works well but if I take the hash password from the DB again it returns false.
const myFunction = async ()=>{
const passwordText = 'abcd123'
const hashedPassword = await bcrypt.hash(passwordText, 10)
console.log(passwordText)
console.log(hashedPassword)
const isMatch = await bcrypt.compare(passwordText, hashedPassword)
console.log(isMatch)
}
myFunction()
Out Put
abcd123
$2b$10$yNuWJBqlV8NjHrmqOfwaSuKDk.rSB9O6KstAmUpS2770GC1Nlyjw.
true
But when I create user with a hash password like this
router.post('/user/signup', async (req, res)=>{
try{
const user = new User(req.body)
const salt = await bcrypt.genSalt(10)
user.password = await bcrypt.hash(user.password, salt)
await user.save().then((user)=>{
res.status(201).send(user)
}).catch((e)=>{
res.send(e)
})
} catch(e){
res.status(500).send()
}
})
and when I compare it in log in route it returns false
router.post("/user/login", async (req, res) => {
const body = req.body;
const user = await User.findOne({ email: body.email });
if (user) {
// check user password with hashed password stored in the database
const validPassword = await bcrypt.compare(body.password, user.password);
if (validPassword) {
res.status(200).json({ message: "Valid password" });
} else {
res.status(400).json({ error: "Invalid Password" });
}
} else {
res.status(401).json({ error: "User does not exist" });
}
});
I tried to create a hash password in user schema like this
userSchema.pre('save', async function(next){
const user = this
if(user.isModified('password')){
user.password = await bcrypt.hash(user.password, 10)
}
console.log('Befor saveing')
next()
})
again it returns false.
I will appreciate any help, thanks.
Update and Solution
Finally, this post solve my problem, everything is working.
When I create a user in the password field I used lowercase: true, and after that, I remove this now bcrypt compare is working I got True return.
I will share my solution, I hope to help you.
LOGIN
exports.ValidateUser = async (req, res, next) => {
const user = await User.findOne({email:req.query.email});
if(user !== null){
const verify_password = await bcrypt.compare(req.query.password,user.password);
if(verify_password){
const token = await generateToken(user);
res.header("x-auth-token",token).send({
token:token
});
}else{
res.status(400).send({message:'Wrong email or password.'});
}
}else{
res.status(404).send({message:"User not found."})
}
}
Create User
exports.createUser = async (req,res,next) => {
const user = new User({first_name: req.body.first_name,
last_name: req.body.last_name,
email: req.body.email,
password: await bcrypt.hash(req.body.password, 10),
roles:req.body.roles});
user.save().then(()=>{
res.status(201).send({message:"User created."})
}).catch((error)=>{
res.status(400).send({error:error});
});
}

JWT sign in Post Request returns Incorrect password error

Currently my project takes sign up requests correctly, and stores emails and encrypted passwords into my MongoDB database. However, when I take the same e-mail and password I signed up with, I get an error telling me that my password is incorrect
I have the following sign in request set up:
module.exports.login_post = async (req, res) => {
// shows us the data that was sent.
// console.log(req.body)
// destructure to just get the email and password from the body
const { email, password } = req.body;
console.log('login called')
try {
const user = await User.login(email, password);
// creates and sends a jwt cookie
const token = createToken(user._id);
res.cookie("jwt", token, { httpOnly: true, maxAge: maxAge * 1000 });
res.status(200).json({ user: user._id });
} catch (err) {
const errors = handleErrors(err);
res.status(400).json({ errors });
}
console.log(email, password)
res.send('user login')
};
In this code I reference User.login, which is imported from my User Model
userSchema.statics.login = async function (email, password){
const user = await this.findOne({ email });
if(user){
const auth = await bcrypt.compare(password, user.password)
if(auth){
return user
}
throw Error('incorrect password')
}
throw Error('incorrect email')
}
Right now, I can register a user, but when I turn around and use the same login and password in Postman I get the error "incorrect password " from my User.login function.
At this point, I am not sure what steps I should be taking in problem solving this. Is there a way to console.log the encyrpted version of the password I try to log in with, so I can make sure I have Bcrypt set up to correctly encrypt the user's password?
Edit: My signup code was requested:
module.exports.signup_post = async (req, res) => {
// destructure to just get the email and password from the body
const { eMail, password } = req.body;
// console.log(email, password)
// add a try catch block
try {
const user = await User.create({
eMail,
password,
words: [
]
});
const token = createToken(user._id);
res.cookie("jwt", token, { httpOnly: true, maxAge: maxAge * 1000 });
// (max age is in seconds and this take milliseconds)
res.status(201).json({ user: user._id });
} catch (err) {
console.log(err)
const errors = handleErrors(err);
// console.log(err);
res.status(400).json({ errors });
}
res.send('new signup')
};
2nd Edit: and this is my middleware the fires before I save a new user and encrypts the password
// hash passwords using SALT
userSchema.pre('save', async function (next){
const salt = await bcrypt.genSalt()
this.password = await bcrypt.hash(this.password, salt)
console.log(this.password)
next()
})
Use below code as your password compare you chnage saltRounds with your bcrypt salt rounds it will compare it with password in database
const comparePassword = (hashedPassword, password) => {
return bcrypt.compareSync(password, hashedPassword);
};
let validations = {
comparePassword,
}
module.exports = validations;

Using bcrypt on Node.js results in validation failed

I am writing code in Node.js to encrypt passwords using bcrypt.
However, if you use bcrypt, you will get an ValidationError: User validation failed: password: Cast to String failed for value "Promise { <pending> }" at path "password"
I do not get this error if I save it as plain text without encryption.
Is there a secret of bcrypt I do not know?
bcrypt (not working)
const bcrypt = require('bcrypt');
sign_up = (req, res, next) => {
const { email, password } = req.body;
const User = User.findOne({ email: email });
if (exUser) {
return res.send('exist user');
}
const hash = bcrypt.hash(password, 8);
const user = new User({
email: email,
password: hash
});
user.save((err) => {
if (err) {
return next(err);
}
res.send('signup success');
});
};
no bcrypt (working)
sign_up = (req, res, next) => {
const { email, password } = req.body;
const User = User.findOne({ email: email });
if (exUser) {
return res.send('exist user');
}
const user = new User({
email: email,
password: password
});
user.save((err) => {
if (err) {
return next(err);
}
res.send('signup success');
});
};
To elaborate on Chris's comment:
It appears that bcrypt.hash is asynchronous, and is returning a Promise.
To fix this, I would recommend using an async function and awaiting the result. MDN page
This may require a newer version of NodeJS than what you are running.
const bcrypt = require('bcrypt');
// Async function allows us to use await
sign_up = async (req, res, next) => {
const { email, password } = req.body;
const User = User.findOne({ email: email });
if (exUser) {
return res.send('exist user');
}
// We await the result of the hash function
const hash = await bcrypt.hash(password, 8);
const user = new User({
email: email,
password: hash
});
user.save((err) => {
if (err) {
return next(err);
}
res.send('signup success');
});
};
Do not use the bcrypt.hashSync function, as while it is running your server will not be able to do anything else.

Resources