Bcrypt compare() always return false - javascript

I have used this code for comparison.
UserSchema.pre('save', async function() {
const salt = await bcrypt.genSalt(10)
this.password = await bcrypt.hash(this.password, salt)
})
UserSchema.methods.comparePassword = async function(candidatePassword) {
const isMatch = await bcrypt.compare(candidatePassword, this.password)
console.log(this.password);
console.log(candidatePassword);
return isMatch
}
I always get an invalid credentials error from the below login function. I have checked by logging the outputs. The problem lies with the compare password functionality.
const login = async(req, res) => {
const { email, password } = req.body
if (!email || !password) {
throw new CustomError.BadRequestError('Please provide email and password')
}
const user = await User.findOne({ email })
if (!user) {
throw new CustomError.UnauthenticatedError('Invalid Credentials')
}
const isPasswordCorrect = await user.comparePassword(password)
if (!isPasswordCorrect) {
throw new CustomError.UnauthenticatedError('Invalid Credentials')
}
if (!user.isVerified) {
throw new CustomError.UnauthenticatedError('Please Verify Your Email ')
}
const tokenUSer = createTokenUser(user)
attachCookiesToResponse({ res, user: tokenUSer })
res.status(StatusCodes.OK).json({ user: tokenUSer })
}

This might be helpful to someone,
I got the same errror while working with postgresql, I replaced the hash password variable with hardcoded hash string and it worked. So I console logged the user password retrieved from the database and noticed that whitespace was included in the result, the number of whitespace included when summed up with length of the user password gives the exact length precision of the password column, so you can either trim the user.password or redefine your database so that it doesn't include whitespace when queried.

Related

How do i Validate old password while updating user password?

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

How to hash password with bcryptjs in node?

I recieve password through req.body and hash it like this :
const { name, email, password, number } = req.body;
let userExist;
userExist = await User.find({ email: email });
if (userExist.length) {
const err = new Error('User already exists');
return next(err);
}
let hashedPass;
try {
hashedPass = await bcrypt(req.body.password, 12);
} catch (e) {
console.log('error here bro');
return next(e);
}
const createdUser = new User({
name,
email,
password: hashedPass,
number,
ads: []
});
It console logs 'error here bro' and I dont know why .
How can I hash password coming from user with bcrypt js ?
You can also add salt to your password in the following way:
const salt = await bcrypt.genSalt(7);
const hashPassword = await bcrypt.hash(req.body.secret, salt);
Solved the problem by adding hash after bcrypt
bcrypt.hash(....)

How do I retrieve an encrypted password from my database with bcrypt?

I have an application with a register and login form. I've managed to get the encrypted password into the database, but i can't seem to get it to work when I want to compare it when logging in. How would I implement bcrypt in my login post method?
Here is my register post where the password is stored successfully:
router.post('/register', (req, res) => {
bcrypt.hash(req.body.password, 10).then((hash) => {
let userData = req.body;
let user = new User(userData);
user.password = hash;
user.save((error, registeredUser) => {
if (error) {
console.log(error);
} else {
let payload = {subject: registeredUser._id};
let token = jwt.sign(payload, 'secretKey');
res.status(200).send({token});
}
});
});
});
And here is my login post:
router.post('/login', (req, res) => {
let userData = req.body;
User.findOne({email: userData.email}, (error, user) => {
if (error) {
console.log(error);
} else {
if(!user) {
res.status(401).send('Invalid Email');
} else
if (user.password !== userData.password) {
res.status(401).send('Invalid Password');
} else {
let payload = {subject: user._id};
let token = jwt.sign(payload, 'secretKey');
res.status(200).send({token});
}
}
});
});
Few things to note here.
Password are usually encrypted using one-way hashing function, which means you shouldn't be expecting to decrypt the saved password back to original text.
In a one way hash function, same hash (encryption output) is created for same input, every time. Eg: If you can encrypt the word "mysimplepassword", the output is going to be the same "xjjklqjlj34309dskjle4" (just a sample) every time.
The method of checking password in such scenarios is:
(a) Store the encrypted password (hash) when its first provided (usually during sign up)
(b) During login, receive the password as input and encrypt it using same encryption method, to obtain the hash
(c) Compare the hash
If you are using bcrypt, you can use bcrypt.compare() to perform these operations
I figured it out and am now comparing the hashed passwords successfully. Here is the new login post:
router.post('/login', (req, res) => {
let userData = req.body;
User.findOne({email: userData.email}, (error, user) => {
if (error) {
console.log(error);
} else {
if(!user) {
res.status(401).send('Invalid Email');
} else {
bcrypt.compare(req.body.password, user.password, function (err, result) {
if (result == false) {
res.status(401).send('Invalid Password');
} else {
let payload = {subject: user._id};
let token = jwt.sign(payload, 'secretKey');
res.status(200).send({token});
}
});
}}
});
});

Trying to update password (GraphQL) "data must be a string and salt must either be a salt string"

I'm new to graphQL and I'm trying to update the user profile password in the backend under my resolvers.js file but I've been stuck at it for a while and I keep getting the same error message.
resolvers.js
updatePassword: combineResolvers(
isAuthenticated,
async (parent, args, context) => {
const { id, newPassword, oldPassword } = args;
const { models, user, jwtSecret } = context;
await models.User.updatePassword(
{ id, newPassword, oldPassword },
createToken({ newPassword }, jwtSecret, API_TIMEOUTS.JWT_TOKEN),
user.emailAddress
);
return models.User.findByEmail(user.emailAddress);
}
)
Index.js (helper)
const generatePasswordHash = async password => {
const saltRounds = 10;
return bcrypt.hash(password, saltRounds);
}
User.updatePassword = async (newPassword, emailAddress) => {
const password = await generatePasswordHash(newPassword);
return User.update(
{ password, resetPasswordToken: null },
{
where: {
emailAddress
}
}
);
};
Error that I'm getting
"data must be a string and salt must either be a salt string or a number of rounds"
User.updatePassword takes only 2 arguments, the first being the password. You are invoking it with 3. The problem is you are providing an object for the password ({ id, newPassword, oldPassword }) and bcrypt doesn't like that

"Error: Illegal arguments: string, undefined" and stop server in node JS

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")
}
});

Categories

Resources