NodeJS: bcrypt is returning false even when the password is correct - sql

I am having trouble with the bcrypt.compare portion of my code. My route is able to hash the password and store the password in the database. The database is able to store 255 characters and I have verified that the password is 60 characters long. Every time I compare the password to the hashed password on the db, I get a false returned on from bycrypt.compare.
Has anyone encountered this and know what I may be doing wrong?
Auth Route for creating the user in the database:
app.post('/register/local', async (req, res) => {
const hashedPassword = await bcrypt.hash(req.body.password, 10) || undefined
const existingLocalUser = await db.User.findOne({ where: { email: req.body.email } }) || undefined
if (!existingLocalUser) {
try {
const newUser = await db.User.create({
given_name: req.body.given_name,
family_name: req.body.family_name,
email: req.body.email,
password: hashedPassword,
}
)
res.redirect('/login')
} catch {
res.redirect('/register')
}
} else if (existingLocalUser.dataValues.google_id) {
const updateUser = await db.User.update(
{ password: hashedPassword },
{ where: { email: req.body.email } }
)
} else {
console.log("You already have an account. Please login.")
res.redirect('/login');
}
})
Local Strategy from Passport:
passport.use(new LocalStrategy( async (username, password, done) => {
const existingLocalUser = await User.findOne({ where: { email: username }})
if (!existingLocalUser) {
console.log("No user exisits")
return done(null, false)
}
console.log("password", password)
console.log("existingLocalUser.password", existingLocalUser.password)
await bcrypt.compare(password, existingLocalUser.dataValues.password, function(error, result) {
if (error) {
return done(error)
} else if (result) {
return done(null, existingLocalUser)
} else {
return done(null, false)
}
})
}
));

bcrypt.compare(password, existingLocalUser.password, function(error, result) {
if (error) {
return done(error)
} else if (result) {
return done(null, existingLocalUser)
} else {
return done(null, false)
}
})
You are trying to use callback and await together, kindly remove await and stick to callbacks or you refactor and use async-await alone

As #cristos rightly pointed out the problem could be that you are mixing up async/await and callbacks. Stick to one pattern.
Here's how your code would be with async/await,
try {
const result = await bcrypt.compare(password, existingLocalUser.password);
if (result) {
return done(null, existingLocalUser);
} else {
return done(null, false);
}
} catch (error) {
return done(error);
}
Also on another note, are you sure you are comparing the correct values?
Going by the code sample you have provided I can see that you are logging,
console.log("password", password)
console.log("existingLocalUser.password", existingLocalUser.password)
However, the values compared in bcrypt.compare() is different,
bcrypt.compare(password, existingLocalUser.dataValues.password)

I figured out why it wasn't working... React or Redux was masking the password with asterisks so changing it to a sting of asterisks which gets hashed..

Related

Return Values from a callback SQL function in node.js

Currently I'm working on a node.js application, with a register function. For this function I need to check a username is already taken or not. Unfortunately the SQL module in node just accepts a callback function from which I cannot send any booleans back.
Here is some code from my controller module:
async function createUser(req, res) {
try {
const salt = await bcrypt.genSalt(); //standard ist 10
const hashedPassword = await bcrypt.hash(req.body.password, salt);
const newUser = {
userName: req.body.username,
userPassword: hashedPassword
};
const userExists = model.checkIfUserExists(newUser.userName);
if (userExists == false){
// create new user
} else {
// Send json back "user already exists
}
res.status(201).json(newUser);
} catch {
res.status(500);
}
}
And here is the code of the model:
function checkIfUserExists(Username){
console.log("Checking if user exists");
let sql = "select * from users where user_name = ?";
db_conn.query(sql, Username, (err, result) => {
if (err){
throw err;
}
console.log(result);
if (result.length > 0){
return true;
} else {
return false;
}
});
}
Unfortunately the "checkIfUserExists" method never returns back a true or false which leads to the "userExists " variable to be null.
I'd like to know how to do return the bollean there or how to solve the problem in a more elegant way.
Please help me to fix this code. Thanks :)
You can either pass a callback to checkIfUserExists or use promises. If I were you, and since you are already using async/await, I would make your return of checkIfUserExists be a promise. So...your code could become
function checkIfUserExists(Username) {
return new Promise((resolve,reject) => {
console.log("Checking if user exists");
let sql = "select * from users where user_name = ?";
db_conn.query(sql, Username, (err, result) => {
if (err) {
throw err;
}
console.log(result);
if (result.length > 0) {
resolve()
} else {
reject()
}
});
})
}
Then, your code that calls this function would be:
async function createUser(req, res) {
try {
const salt = await bcrypt.genSalt(); //standard ist 10
const hashedPassword = await bcrypt.hash(req.body.password, salt);
const newUser = {
userName: req.body.username,
userPassword: hashedPassword
};
await model.checkIfUserExists(newUser.userName).catch(() => {
// Send json back "user already exists
});
// create user
res.status(201).json(newUser);
} catch {
res.status(500);
}
}
First check your catch statement and also add await before model.checkIfUserExists(newUser.userName)
async function createUser(req, res) {
try {
const salt = await bcrypt.genSalt(); //standard ist 10
const hashedPassword = await bcrypt.hash(req.body.password, salt);
const newUser = {
userName: req.body.username,
userPassword: hashedPassword
};
const userExists = await model.checkIfUserExists(newUser.userName);
if (userExists == false){
// create new user
} else {
// Send json back "user already exists
}
res.status(201).json(newUser);
} catch(ex) {
res.status(500);
}
}
return promise from this function:
function checkIfUserExists(Username){
return new Promise((resolve, reject) => {
console.log("Checking if user exists");
let sql = "select * from users where user_name = ?";
db_conn.query(sql, Username, (err, result) => {
if (err){
return reject(err);
}
console.log(result);
if (result.length > 0){
return resolve(true);
} else {
return resolve(false);
}
});
})
}

stuck on 400 bad request, method might be incorrect?

Hello im currentenly stuck and im not quite sure whats wrong
my postman login is all fine but my backend dont accept anything so im pretty sure there is something wrong with my method
export default {
data() {
return {
loading: false,
error: null,
login: {
email: "",
password: "",
}
}
},
methods: {
UserLogin: function() {
this.loading = true;
this.axios.post('http://localhost:3000/login', {user: this.login})
.then((res) =>{
this.$cookies.set('jwt', res.data.jwt);
this.$cookies.set('isAdmin', res.data.isAdmin);
this.$router.push('/dashboard');
}).catch(err => {
//fejl
this.error = err.response.data.message;
});
this.loading = false;
},
CheckForNullInObject: function(obj) {
for (let key in obj) {
if(obj[key] == null || obj[key] == "") return false;
}
return true;
}
}
and my backend
router.post('/', async (req, res) => {
if(!req.body.email || !req.body.password) {
res.status(400).json({
message: "missing values1"
});
return
}
always hits the missing values1 no matter what I write
You've POSTed the login data under user, but your backend code doesn't read that property.
Either update your frontend to send the data directly (without user):
this.axios.post('http://localhost:3000/login', { ...this.login })
Or update the backend to read the data from user:
if(!req.body.user.email || !req.body.user.password)

Can someone please tell me where can i write my bcrypt-hashing function?

exports.postLogin = (req, res) => {
let { email, pass } = req.body;
console.log(email);
User.findOne({ email }, (err, result) => {
console.log(email, pass, result.pass);
if (err) {
res.json({ status: 'failed', message: err });
} else if (!result) {
res.json({ status: 'failed', message: 'email or password are wrong' });
} else {
bcrypt.compare(pass, result.pass).then(async (isPassCorrect) => {
if (isPassCorrect) {
const token = await signToken(result.id);
res.json({
status: 'success',
message: 'you logged in !!',
token,
});
} else res.json({ status: 'failed', message: 'email or password are wrong!' });
});
}
});
};
Your quetsion is not really clear about what you are trying to do, so I'm guessing into the black.
If I get you right, you are looking for the right place in order to hash a password before it gets saved, so you can use bcrypt.compare() on the encrypted password, is that right?
If yes, you could use mongooses pre-hook to hash the password before mongoose actually saves a document. To accomplish this add this to your model file
User.pre('save', async function (next) {
await bcrypt.genSalt(12).then(async salt => {
this.password = await bcrypt.hash(this.password, salt).catch(err => {
return next(err)
})
}).catch(err => {
return next(err)
})
})

after successfully register, i'm not able to login in express

after successful register with passport in express, when i try to login. it failed and i don't know which code is causing error. please help.
here is my code.
router.post('/register',function(req,res){
//fetch user info
var firstName=req.body.firstName,
lastName = req.body.lastName,
mobile= req.body.mobile,
email = req.body.email,
password = req.body.password,
newsConsent = req.body.newsConsent;
var userInfo = {firstName: firstName, lastName: lastName, mobile: mobile, email:email, newsConsent: newsConsent };
//register and create user
User.register(new User(userInfo), password, function(error, userCreated)
{
if (error)
{
console.log(error);
// req.flash("error", error.message);
return res.render("auth/register");
}
else
{
req.login(userCreated, function(err) {
if (err) {
console.log(err);
return next(err);
}
console.log(userCreated);
return res.redirect('/');
});
}
});
});
//login route
router.post("/login", passport.authenticate("local",
{
successRedirect: "/",
failureRedirect: "/register"
}), function(req, res){
console.log(req.body);
});
also please tell me how to know about the error in passport
You need declare your strategy, serialize and deserialize. Here's my code. You can edit it as you need. FYI, I was using 'nip_nim' instead of 'username', so I set "usernameField" as nip_nim. Here I also use 'flash' package to save my notification data.
passport.use(new LocalStrategy({
usernameField: 'nip_nim',
passReqToCallback: true
}, function (req, nip_nim, password, done) {
var params = {
nip_nim: nip_nim
}
var user = new User_Model(params);
user.getDataUserByNIPorNIM()
.then(function (result) {
if (!helper.isExist(nip_nim) || !helper.isExist(password)) {
return done(null, false, req.flash('message_err', 'NIM/NIM dan password tidak boleh kosong.'));
}
if (!result) {
return done(null, false, req.flash('message_err', 'NIP/NIM yang anda masukkan salah.'));
}
if (!bcrypt.compareSync(password, result.password)) {
return done(null, false, req.flash('message_err', 'Password yang anda masukkan salah.'));
}
return done(null, result);
})
}));
//serialize and deserialize passport
passport.deserializeUser(function (nip_nim, done) {
var params = {
nip_nim: nip_nim
}
var user = new User_Model(params);
user.getDataUserByNIPorNIM()
.then(function (result) {
done(null, result);
})
});
passport.serializeUser(function (req, user, done) {
done(null, user.nip_nim, req.flash('message_success', 'Welcome, ' + user.nama_unit_org + "."));
});
ok. i found the culprit. it's not passport, it's mongoose schema.
i have to add {index : true} in username.
`username : {type:String, unique: true, index: true},`.
after that everything works fine.

Bcrypt + Sequelize password not saving as hash in DB

Sequelize + Bcrypt not storing passwords in DB as hash
As the title says, whenever I attempt to store a user into my SQLite DB the console outputs the password as a hash but when I look into the DB with DBbrowser I can see the plaintext password.
Model
// const Promise = require('bluebird')
const bcrypt = require('bcrypt')
async function hashPassword (user, options) {
if (!user.changed('password')) {
return 0
}
const SALT_FACTOR = 8
await bcrypt.hash(user.password, SALT_FACTOR, (err, hash) => {
if (err) {
console.log(err)
}
// user.setDataValue('password', hash)
user.password = hash
console.log(user)
})
}
module.exports = (sequelize, DataTypes) => {
const User = sequelize.define('User', {
email: {
type: DataTypes.STRING,
unique: true
},
password: DataTypes.STRING
}, {
hooks: {
beforeSave: hashPassword,
beforeCreate: hashPassword
}
})
User.prototype.comparePassword = function (password) {
bcrypt.compare(password, this.password, function (res, err) {
if (res) {
console.log(res)
} else {
console.log(err)
}
})
return bcrypt.compare(password, this.password)
}
return User
}
Controllers
module.exports = {
async register (req, res) {
try {
const user = await User.create(req.body)
const userJson = user.toJSON()
res.send({
user: userJson,
token: jwtSignUser(userJson)
})
} catch (err) {
// e-mail already exists or such
res.status(400).send({
error: 'This email address is already in use'
})
}
},
async login (req, res) {
try {
// Grab user input
const { email, password } = req.body
const user = await User.findOne({
where: {
email: email
}
})
// Check to see if user is in db
if (!user) {
res.status(403).send({
error: 'the login information was incorrect / Not Found'
})
}
// Check to see if password is valid
const isPasswordValid = await user.comparePassword(password)
if (!isPasswordValid) {
return res.status(403).send({
error: 'The login information was incorrect'
})
}
// return user using toJSON()
const userJson = user.toJSON()
res.send({
user: userJson,
token: jwtSignUser(userJson)
})
} catch (e) {
res.status(500).send({ error: 'An error occured attempting to login' })
console.log(e)
}
}
}
To elaborate a little more, whenever I create a user, I receive the following:
{
"user": {
"id": 1,
"email": 'test#test.com",
"password": "$2b$08$SYYXU/GDSCFsp3MVeuqrduI0lOLHeeub7whXiaMMoVxO53YJry.1i",
"updatedAt": "2018-09-07T22:44:12.944Z",
"createdAt": "2018-09-07T22:44:12.944Z"
},
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiZW1haWwiOiJTVVBCUkhVQGxvbC5jb20iLCJwYXNzd29yZCI6IiQyYiQwOCRTWVlYVS9HRFNDRnNwM01WZXVxcmR1STBsT0xIZWV1Yjd3aFhpYU1Nb1Z4TzUzWUpyeS4xaSIsInVwZGF0ZWRBdCI6IjIwMTgtMDktMDdUMjI6NDQ6MTIuOTQ0WiIsImNyZWF0ZWRBdCI6IjIwMTgtMDktMDdUMjI6NDQ6MTIuOTQ0WiIsImlhdCI6MTUzNjM2MDI1MywiZXhwIjoxNTM2OTY1MDUzfQ.mDaeIikzUcV_AGTuklnLucx9mVyeScGpMym1y0kJnsg"
}
Which to me says the DB successfully hashed my password, and stored it. The overhanging issue for me with this is the fact that I believe it's causing the bcrypt.compare function to spit out 'false'. As always, any insight or help would be greatly appreciated!
I'm pretty sure that this answer is too late for you, but might help others landing on this same question.
The main issue I can see is how you are using the async/await pattern. Changing this:
async function hashPassword (user, options) {
if (!user.changed('password')) {
return 0
}
const SALT_FACTOR = 8
await bcrypt.hash(user.password, SALT_FACTOR, (err, hash) => {
if (err) {
console.log(err)
}
// user.setDataValue('password', hash)
user.password = hash
console.log(user)
})
}
to this, worked for me:
async function hashPassword(user, options) {
if (!user.changed("password")) {
return 0;
}
user.password = await bcrypt.hash(user.password, SALT_FACTOR);
}
Can you please try to add only one hook
hooks: {
beforeSave: hashPassword,
}
Because I think your password is getting hashed two times. as beforeSave and beforeCreate both hooks get executed.
Hope it helps