Bcrypt compareSync is always returning False - node.js

trying the user Auth first time and able to create the users, it seems the bcrypt password hash is working when registering the user as I can see the hashed password in the DB, However when I am trying to login with the same credential, getting an error Invalid email or password based on my code below:
const {
create,
getUserByUserId,
getUserByUserEmail,
} = require('./user-services')
const {genSaltSync, hashSync, compareSync} = require('bcrypt')
const {sign} = require('jsonwebtoken')
module.exports = {
createUser: (req, res) => {
const body = req.body;
const salt = genSaltSync(10);
body.password = hashSync(body.password, salt);
create(body, (err, results) => {
if (err) {
console.log(err);
return res.status(500).json({
success: 0,
message: "Database connection errror"
});
}
return res.status(200).json({
success: 1,
data: results
});
});
},
login: (req, res) => {
const body = req.body;
console.log(body.user_email)
getUserByUserEmail(body.user_email, (err, results) => {
if (err) {
console.log(err);
}
if (!results) {
return res.json({
success: 0,
data: "* Invalid email or password *"
});
}
const result = compareSync(body.password, results.password);
console.log(result)
console.log(results.password)
console.log(body.password)
if (result) {
results.password = undefined;
const jsontoken = sign({ result: results }, "test1234", {
expiresIn: "1h"
});
return res.json({
success: 1,
message: "Login successfully",
token: jsontoken
});
} else {
return res.json({
success: 0,
data: "Invalid email or password"
});
}
});
},
}
When console log, I can see the body. password and response from DB. Here is what I am getting in the console.log

Solved it. Modified MySQL column for Password to VARCHAR(1024). it was
limited to VARCHAR(56)

Related

keeps getting "Illegal arguments: undefined, string at Object.bcrypt.hashSync"

I've been struggling with Bcrypt on my MERN project I'm trying to create an authentication system I'm trying to run tests on Postman and I'm not sure why do I keep getting the error: "Illegal arguments: undefined, string at Object.bcrypt.hashSync"
this is my postman request:
this is the Controller Code:
const config = require("../config/auth.config");
const db = require("../models");
const User = db.user;
const Role = db.role;
var jwt = require("jsonwebtoken");
var bcrypt = require("bcryptjs");
exports.signup = (req, res) => {
const user = new User({
username: req.body.username,
email: req.body.email,
password: bcrypt.hashSync(req.body.password, 8),
});
user.save((err, user) => {
if (err) {
res.status(500).send({ message: err });
return;
}
if (req.body.roles) {
Role.find(
{
name: { $in: req.body.roles },
},
(err, roles) => {
if (err) {
res.status(500).send({ message: err });
return;
}
user.roles = roles.map((role) => role._id);
user.save((err) => {
if (err) {
res.status(500).send({ message: err });
return;
}
res.send({ message: "User was registered successfully!" });
});
}
);
} else {
Role.findOne({ name: "user" }, (err, role) => {
if (err) {
res.status(500).send({ message: err });
return;
}
user.roles = [role._id];
user.save((err) => {
if (err) {
res.status(500).send({ message: err });
return;
}
res.send({ message: "User was registered successfully!" });
});
});
}
});
};
exports.signin = (req, res) => {
User.findOne({
username: req.body.username,
})
.populate("roles", "-__v")
.exec((err, user) => {
if (err) {
res.status(500).send({ message: err });
return;
}
if (!user) {
return res.status(404).send({ message: "User Not found." });
}
var passwordIsValid = bcrypt.compareSync(
req.body.password,
user.password
);
if (!passwordIsValid) {
return res.status(401).send({ message: "Invalid Password!" });
}
var token = jwt.sign({ id: user.id }, config.secret, {
expiresIn: 86400, // 24 hours
});
var authorities = [];
for (let i = 0; i < user.roles.length; i++) {
authorities.push("ROLE_" + user.roles[i].name.toUpperCase());
}
req.session.token = token;
res.status(200).send({
id: user._id,
username: user.username,
email: user.email,
roles: authorities,
});
});
};
exports.signout = async (req, res) => {
try {
req.session = null;
return res.status(200).send({ message: "You've been signed out!" });
} catch (err) {
this.next(err);
}
};
The error message:
Illegal arguments: undefined, string at Object.bcrypt.hashSync wants to say that you're passing undefined as an argument to the hashSync function. We need to fix this error.
Take a closer look at this line where the error occurs:
password: bcrypt.hashSync(req.body.password, 8),
req.body.password is undefined, you can verify it by console.log(req.body.password). What's wrong is that you are sending data as URL parameters. So req.body is an empty object and req.body.password is undefined.
In Postman, select the Body tab, choose JSON format, then type your data as a JSON object. Then, in your code, use express.json() middleware to parse requests in JSON format. You'll have the desired output.
You can see my example request in Postman below:

Node.js bcrypt compare problem only return false

I want to do my login API with Node.js and MongoDB and when I compare my pass from input to the one that's in the db I always get false I read other post on StackOverFlow but didn't helped me.
I think I also found the problem: When I use hash on my password input to check it manually with the one from db at every request is onatherone.
So maybe that's the problem but I don't know how to solve. I read a lot about this but still cant solve here is my code:
const match = await bcrypt.compare(password, user.password, (res) => {console.log(res)}) //false
my login api
router.post('/login', body('email').isEmail(), body('password').exists(), async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() })
}
const { email, password } = req.body
const user = await User.findOne({ email })
if (!user) {
return res.status(401).json({ "err": "invalid credentials" })
}
// const match = await bcrypt.compare(password, user.password).then(function (res) { console.log(res) })
const match = await bcrypt.compare(password, user.password);
console.log(match)
})
and here is the register api
router.post("/register", body("email").isEmail(), body("password").isLength({ min: 5 }), body("username").isLength({ min: 1 }), async (req, res) => {
const { email, username, password } = req.body
const errors = validationResult(req);
const saltRounds = 10;
try {
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() })
}
//check if the user exist
const duplicated = await User.findOne({ email })
if (duplicated) { return res.status(401).json({ "err": "Email is taken" }) }
const user = new User({ username, email, password })
//crypt pass
user.password = bcrypt.hashSync(process.env.secret, saltRounds);
//generate token with jwt
const payload = {
id: user.id
}
jwt.sign({
payload,
}, process.env.jwtSecret, { expiresIn: '999h' }, (err, token) => { console.log(token) });
//save the user
await user.save()
res.status(200).send("User Stored")
} catch (error) {
res.status(500).send(error.body)
}
})
Your problem is that you using bcrypt.hash in the wrong way.
It seems like you provide this method kind of key, which you shall not provide.
This method accepts the value to hash, and saltRounds.
So you basically need to change your Registration API code to:
router.post("/register", body("email").isEmail(), body("password").isLength({ min: 5 }), body("username").isLength({ min: 1 }), async (req, res) => {
const { email, username, password } = req.body
const errors = validationResult(req);
const saltRounds = 10;
try {
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() })
}
//check if the user exist
const duplicated = await User.findOne({ email })
if (duplicated) { return res.status(401).json({ "err": "Email is taken" }) }
const user = new User({ username, email, password })
//crypt pass
user.password = bcrypt.hashSync(password, saltRounds);
//generate token with jwt
const payload = {
id: user.id
}
jwt.sign({
payload,
}, process.env.jwtSecret, { expiresIn: '999h' }, (err, token) => { console.log(token) });
//save the user
await user.save()
res.status(200).send("User Stored")
} catch (error) {
res.status(500).send(error.body)
}
}
And more specific, you store the password with:
user.password = bcrypt.hashSync(password, saltRounds);
try use Promise for this
const match = await new Promise((resolve, reject) => {
bcrypt.compare(password, user.password, function(error, res){
if (error) { reject(error); }
resolve(res);
})
})

Issue in executing callback and saving data to mysql db

I am trying to authenticate using google plus api and trying to save the google user details in the callback function from google plus api but due to some reason i am unable to pass values from google plus api response to callback request.
Snippet from Router.js
router.get("/auth/google", passport.authenticate('google', { scope: ['profile','email'] }));
router.get("/auth/google/callback" , passport.authenticate('google') , googleInsert);
Snippet from User.controller.js
const {
getGoogleUserByEmail,
createGoogleUser,
} = require("./user.service.js");
module.exports = {
googleInsert: (req, res) => {
body = req.body;
body.googleId = req.body.profile.id;
body.firstName = req.body.profile.name.givenName;
body.lastName = req.body.profile.name.familyName;
body.email = req.body.profile.emails[0].value;
body.photoUrl = req.body.profile.photos[0].value;
//const salt = genSaltSync(10);
//body.password = hashSync(body.password, salt);
//verify if email id exists
getGoogleUserByEmail(body.email, (err, results) => {
if (err) {
console.log(err);
}
//Email id already registered and exists in db
if (results) {
console.log("Google Email already exists");
return res.status(409).json({
success: 0,
data: "Google Email already exist",
});
}
console.log(
"Google Email id is not registered, proceed with Google User Insert"
);
if (!results) {
createGoogleUser(body, (err, createResults) => {
console.log(body);
if (err) {
console.log(err);
return res.status(500).json({
success: 0,
message: "Database connection error",
});
}
if (createResults.affectedRows == 1) {
console.log("inside succcess is 1");
//Insert into UserRole Table
createUserRole(
createResults.insertId,
(body.role_id = 2),
(err, results) => {
console.log(results);
if (err) {
console.log(err);
return res.status(500).json({
success: 0,
message: "DB error",
});
}
if (!err) {
console.log("Google User created successfully");
return res.status(200).json({
success: 1,
data: createResults,
});
}
}
);
}
});
}
});
},
};
Passport.js
const passport = require("passport");
const GoogleStrategy = require("passport-google-oauth20").Strategy;
const keys = require('../config/keys');
passport.use(
new GoogleStrategy(
{
clientID: process.env.clientID,
clientSecret: process.env.clientSecret,
callbackURL: "http://localhost:1111/api/users/auth/google/callback",
//passReqToCallback: true
},
(accessToken, refreshToken, profile, callback) => {
console.log("access token", accessToken);
console.log("refresh token", refreshToken);
console.log("profile", profile);
console.log("callback", callback);
}
)
);
The issue i am getting is i am not sure how to get the value from google authentication to be used in callback request and am not sure if callback is working or not. After i select the email id from google plus api client screen, it just goes into infinite loop and no data is getting inserted into db.
body = req.body;
body.googleId = req.body.profile.id;
body.firstName = req.body.profile.name.givenName;
body.lastName = req.body.profile.name.familyName;
body.email = req.body.profile.emails[0].value;
body.photoUrl = req.body.profile.photos[0].value;

Update a property in document in an Express route (Mongoose, MongoDB, Express)

I've successfully set up the registration and login functionality using Express, MongoDB and Mongoose.
I would like to log when the user last visited the site once the user's credential is accepted in a lastConnection property of the user document,
I tried but "lastConnection" is null (see the line below where I add a comment)
router.post("/login", async function(req, res) {
const { errors, isValid } = validateLoginInput(req.body);
if (!isValid) {
return res.status(400).json(errors);
}
const email = req.body.email;
const password = req.body.password;
const user = await User.findOne({ email }).then(user => {
if (!user) {
errors.email = "Email already exists";
}
console.log("user ", user); <-- returns an object with the datas of user
bcrypt.compare(password, user.password).then(isMatch => {
if (isMatch) {
const payload = {
id: user.id,
name: user.name
};
user.lastConnection = new Date(); <-- doesn't work
jwt.sign(
payload,
keys.secretOrKey,
{
expiresIn: 7200
},
(err, token) => {
res.json({
success: true,
token: "Bearer " + token
});
}
);
} else {
errors.password = "Password is not correct";
// return res
// .status(400)
// .json({ passwordincorrect: "Password incorrect" });
}
});
});
return {
errors,
isValid: isEmpty(errors)
};
});
Any ideas? I think I have to do an update but I don't know where to put it
Try replacing user.lastConnection = new Date(); with
user.update({ lastConnection: new Date() })
.then( updatedUser => {
console.log(updatedUser)
// put jwt.sign code here
})

Why does transaction fails with already rolled back when user inputs in wrong email

I'm authorizing emails in the database but when I input wrong email it throws Transaction cannot be rolled back because it has been finished with state: commit
export const signin = async (req, res) => {
const { email, password } = req.body;
const transaction = await db.sequelize.transaction();
try {
const user = await db.User.findOne({ where: { email } }, { transaction });
await transaction.commit();
const passBool = Auth.comparePassword(password, user.password);
if (user && passBool) {
return res.json({
success: 1,
user,
message: 'signed in'
});
}
res.json({ success: 0, message: 'wrong username or password' });
} catch (ex) {
await transaction.rollback();
res.json({ success: 0, message: 'wrong username or password' });
}
};
I'm not sure exactly why rolling back doesn't work in your example, but you can try:
A transaction should be passed in the options object of the query:
const user = await db.User.findOne({ where: { email }, transaction });
You can try using managed transaction, to avoid manual handling of commit/rollback:
export const signin = async (req, res) => {
const { email, password } = req.body;
db.sequelize.transaction(async transaction => {
const user = await db.User.findOne({ where: { email }, transaction });
const passBool = Auth.comparePassword(password, user.password);
if (user && passBool) {
return res.json({
success: 1,
user,
message: 'signed in'
});
}
res.json({ success: 0, message: 'wrong username or password' });
}).catch(err => {
res.json({ success: 0, message: 'wrong username or password' });
});
};
solved this, it would fail if i had inserted in wrong request body params

Resources