I am getting a bcrypt error stating that data and hash arguments are required, referencing line #44 in my routes.js file. From what I can tell, I am passing that information: the first parameter to bcrypt.compare is the user entered password, and the second is the hashed password retrieved from the db. What am I doing wrong?
bcrypt.compare(req.params.password, user.password, function...
routes.js
'use strict'
var express = require('express');
var router = express.Router();
var User = require('../app/models/user');
//password hashing
var bcrypt = require('bcrypt');
var count = 0;
router.use(function(req, res, next) {
count++;
console.log('API hit count = %s', count);
next();
});
// /users post(create new user) get(specific user)
router.route('/users')
.post(function(req,res) {
var user = new User();
user.username = req.body.username;
user.password = bcrypt.hashSync(req.body.password, 10);
//save the user and checkfor errors
user.save(function(err) {
if (err) {
res.send(err);
} else {
res.json({message: "User created!"});
}
});
})
router.route('/users/:username')
.get(function(req, res) {
var query = {
username: req.params.username,
};
User.findOne(query, function(err, user) {
if (err) {
res.send(err);
} else {
bcrypt.compare(req.params.password, user.password, function(err, res) {
if(err) {
console.log('Comparison error: ', err);
}
})
res.json(user);
}
});
})
bcrypt.compare takes 3 parameters; passwordToCheck, passwordHash, and a callback, respectively. (Check the documentation for examples)
This error means one or both of the first 2 parameters are either null or undefined. Therefore, make sure both of them are passed correctly. (Not as null or undefined)
Why do we face this error?
bcrypt Error: data and hash arguments required
Example:
bcrypt.compare(first, second)
Ans:
because either second key hash password does not exist (null or undefined) or first, which are compared to each other.
I used
const user = await User.find({email: req.body.email}) //which returned all users
//and unless i reference the first user in index 0, i can't pass user.password to the //bcrypt compare method because it's not a string
I changed it to
await User.findOne({email: req.body.email})//from which i can use user.password in the //bcrypt compare method
const passwordMatch = await bcrypt.compare(password, user.password);
Make sure you are giving raw password and hash password. This will return a boolean value.
I was having the same error when I was working with node js and mongoose. It was caused by attribute added to password called select: false in user model.
After remove it, it works.
I had the same error and the problem was a missing await when calling the function that reads from database
the steps for this problem :
1-ensure that the bcrypt function is have awir before it
2- if the problem is still exist ,then the problem is in the database (mongodb),try to create new database
an example:
const match = await bcrypt.compare(password,userValid.password);
if (match) {
res.send("login successful")
}else{
res.send("wrong password")
}
}
I was having the same issue, but I was using the synchronous form of bycrypt.compare(), which is bcrypt.compareSync(), so I changed it to bcrypt.compare() and it works perfectly.
Use
findOne({})
instead of
find()
Try console.log() to view and verify the data.
try {
let match = await bcrypt.compare(password, user.password)
if(!match){
return res.json({mass: "invalid Created"})
}else{
res.send('Wrong password')
}
console.log('success fulli', user)
res.render('pages/auth/login', {title: 'Login In Your Account'})
} catch(e) {
console.log(e)
next(e)
}
The problem also can appear when you forget to add await when loading data from the database.
I got the same error after forgetting to add "await".
let user = User.findOne({ username: req.body.username });
let user = await User.findOne({ username: req.body.username });
I also have this problem i set for password select:false in user model and solved by adding select('+password') to login route
i know all the questions are solved but maybe someone finds this code works for him
const passwordMatch = await bcrypt.compare(password, user.rows[0].s_password);
The name after the dot it's the name you use in your database, it's the field
Related
const express = require('express');
const router = express.Router();
require('../db/conn');
const User = require('../model/userSchema');
router.get('/', (req, res) => {
res.send(`Hello World from the server from router.`);
});
router.post('/register', async (req, res) => {
const { name,email,phone,work,password,cpassword } = req.body;
if(!name || !email || !phone || !work || !password || !cpassword){
return res.status(422).json({error:"please fill all the fields data.."});
}
try {
const userExist = await User.findOne({ "$or": [ { email: email }, { phone: phone} ] })
if(userExist.email==email){
return res.status(422).json({error:"Email ID is already exist."});
}else if(userExist.phone==phone){
return res.status(422).json({error:"Mobile no is already exist."});
}
const user = new User({name,email,phone,work,password,cpassword});
const userRegister = await user.save();
if(userRegister){
res.status(201).json({message:"User Registered Successfully."});
}else{
res.status(500).json({error:"Failed to regsiter user."});
}
} catch (err) {
console.log(err);
}
});module.exports = router;
I write the code for checking email and mobile present or not in database. Actually i want to check differently not in a single statement like Email or mobile is already present. So i write this code but for checking it worked fine but when i put all unique data than one error is coming. data is not stored in database. Error is
TypeError: Cannot read properties of null (reading 'email') at E:\MERN Project\Server\router\auth.js:20:22 at processTicksAndRejections (node:internal/process/task_queues:96:5)
I think the problem is how you create your new record, try instead of
const user = new User({name,email,phone,work,password,cpassword});
const userRegister = await user.save();
to use the schema to create the record.
const user = await User.create({name,email,phone,work,password,cpassword});
await user.save();
actually if you do not change the any property after creation you can skip the save.
The easiest way to achieve this would be to use validator packages. So, the data won't get save if all conditions are not satisfied.
I recommend using 'joi'. Please go through the documentation for a deeper understanding.
https://www.npmjs.com/package/joi
So let's say I want to make a Mongoose query to a database, inside of an Express post route:
app.post("/login",(req,res)=>{
const username = req.body.username
const password = req.body.password
User.find({username:username},(err,user)=>{
if (err) handleError(err)
//if user exists
if (user.length) {
//check password
if (user.password === password) {
//assign jwt, redirect
} else {
//"username/password is incorrect"
}
} else {
//"username/password is incorrect"
}
})
})
My concern is the handleError function. I'm not quite sure what kind of errors could even happen in Mongoose since it's just a simple query, but what should be included in the handleError function? And what response should I send to the user at that point?
You should in my opinion:
Use promises with async/await.
Don't catch any error(s) in your middleware and handle errors in the top-level express error handler. More on this here.
In your top-level express error handler, depending on the environment either return a simple message like: return res.status(500).json({ message: "Our server are unreachable for now, try again later." }); if this is in production. If you're in a local environment, return a JSON payload with the error in it like: return res.status(500).json({ err: <Error> });.
To sumerize, your code should look something like this:
app.post('/login', async (req, res) {
// ES6 Destructuring
const { username, password } = req.body;
// Use findOne instead of find, it speeds up the query
const user = await User.findOne({ username });
if (!user || (user.password !== hashFunction(password))) {
return res.status(403).json({ message: 'Bad credentials' });
}
// assign JWT and redirect
});
You can just send an error response with descriptive message related to Mongoose response.
app.post("/login",(req,res)=>{
const username = req.body.username
const password = req.body.password
User.find({username:username},(error,user)=>{
if (error){
return res.status(400).json({message:"Can not perform find operation.", error: error });
}
//if user exists
if (user.length) {
//check password
if (user.password === password) {
//assign jwt, redirect
} else {
//"username/password is incorrect"
}
} else {
//"username/password is incorrect"
}
})
})
I am currently working on a login system with Nodejs, Express & MongoDB. Everything works except the values in the database are coming up as undefined. At the two console.log statements where "database ___" is stated, the result is undefined. Not too sure why, from some testing it seems that the user inputted values work fine so I don't know why it's returning undefined.
app.post("/login", (req, res) => {
//Get user fields
const userEmail = req.body.loginEmail;
const userPass = req.body.loginPassword;
//Is user in database?
User.find({ email: userEmail }, (err, user) => {
console.log("database email: " + user.email)
if (!err) {
//Compare password to database password
bcrypt.compare(userPass, user.password, (err, result) => {
console.log("database password: " + user.password);
//If user pass in database, check if verified & redirect to success
if (userPass === user.password) {
if (user.isVerified) {
res.redirect("/success");
} else {
res.send(
"You are not verified. Please check your email to access your account."
);
}
} else {
res.send("Incorrect password");
}
});
} else {
res.send(err);
}
});
});
Mongoose will return an array as the second argument to the callback function when you use find(). If you use findOne() a single document will be returned instead.
I'm trying to retrieve username from mysql database, the below code can successfully retrieve the username. However, when err occurs, code doesn't redirect to /signin. The page redirect to /admin instead. Though, if I add
res.redirect('/signin')
just before the last curly bracket, it will redirect to the signin page, but it won't able to retrieve the username.
I want it to redirect to signin page, how?
const connection = require('./connection')
const signin = (req, res) => {
var email = req.body.email
var password = req.body.password
let queryStr = `select username from users where email='${email}' and password='${password}'`
return connection.query(queryStr, (err, rows, fields) => {
if (err) {
res.redirect('/signin')
} else {
req.session.email = email
res.json(rows[0])
}
})
}
module.exports = signin
I think it has to do with async because the code execute the last line then go back to the else statement. I think that's why it goes to /admin page instead. but not fixed yet.
connection.js
const mysql=require('mysql')
var connection=mysql.createConnection({
host:'localhost',
user:'root',
password:'root',
database:'essencejoin',
})
connection.connect()
connection.query('SELECT 1 + 1 AS solution', function (err, rows, fields) {
if (err) throw err
console.log('The solution is: ', rows[0].solution)
})
module.exports=connection
Actually, You're Query is correct, But query doesn't return any rows. So if user not found on username table. It needs to signin page(This is your question correct?), For that you have to update the code like following,
const connection = require('./connection')
const signin = (req, res) => {
var email = req.body.email;
var password = req.body.password;
let queryStr = `select username from users where email='${email}' and password='${password}'`;
return connection.query(queryStr, (err, rows, fields) => {
if (err) {
res.redirect('/signin');
} else if(!rows.length) {
res.redirect('/signin');
}else {
req.session.email = email;
res.json(rows[0]);
}
})
}
module.exports = signin
It looks your code is being executed after you have returned it. You can use promisified version of the same code.
use mysql-promise. this is promisified wrapper around the same library you are using. then Your code will look something like this:
// install mysql-promise
npm i mysql-promise
connection.js
const mysql = require("mysql-promise");
async function getDBConn() {
const connection = mysql.createConnection({
host: "localhost",
user: "root",
password: "root",
database: "essencejoin"
});
await connection.connect();
return connection;
}
module.exports = getDBConn;
then use it like this:
//signin.js
const signin = (req, res) => {
const email = req.body.email;
const password = req.body.password;
const connection = getDBConn();
let queryStr = `select username from users where email='${email}' and password='${password}'`;
try {
await connection.query(queryStr);
req.session.email = email;
res.json(rows[0]);
} catch (error) {
console.log(error);
res.redirect("/signin");
}
};
module.exports = signin;
disclaimer: I have not tested this, even if this does not work this should give you a fair idea how to make it work
Without knowing too much about your project, I think you want to look into adding a status code with the express redirect.
index(req, res, next) {
topicQueries.getAllTopics((err, topics) => {
if (err) {
res.redirect(500, "static/index");
} else {
res.render("topics/index", { topics });
}
});
}
Something like that. Also, look out for other simple mistakes in your project, that may cause this, that deal with Express.
https://expressjs.com/en/api.html#res.redirect
I am very new to coding and am writing a personal project using node.js, express, mongoDB, and mongoose. I wrote most of it myself, however I hired someone to help me with the more advanced parts. I have lost contact with him and went back under the hood to create an admin panel I could use to write blog posts and other things. I am trying to write a middleware that only allows myself access to the route. However it is not working.
function adminAuth(req, res, next){
if(req.user.isAdmin){
return next();
} else {
res.redirect("/");
}
}
I am a bit confused of the syntax he has used to create a user schema and I am not sure how to add this isAdmin key value pair. Any help updating my users with an isAdmin key value would be extremely appreciated, and also helping me finish the middleware as (req.user.isAdmin) is not working! (If I do not provide the necessary code, please excuse my inexperience and tell me what you would like to see).
Here is the Auth route the coder I hired wrote that I am having trouble deciphering how to pass in new data to the user model.
const isAdmin = false;
const passwordHash = await bcrypt.hash(req.body.password, saltRounds);
const db = client.db(dbName);
const col = db.collection('users');
const user = {
email, firstName, lastName, password: passwordHash, isAdmin,
};
local strategy
module.exports = function localStrategy() {
passport.use(new Strategy(
{
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true
}, (req, email, password, done) => {
const url = process.env.MONGOLAB_URI;
const dbName = 'giftgrab';
(async function addUser() {
let client;
try {
client = await MongoClient.connect(url);
const db = client.db(dbName);
const col = db.collection('users');
const user = await col.findOne({ email });
debug('Found user by email');
debug(user);
if (!user) {
req.flash('error', 'The username or password is wrong');
done(null, false);
} else {
const match = await bcrypt.compare(password, user.password);
if (match) {
done(null, user);
} else {
req.flash('error', 'The username or password is wrong');
// we pass null because it did not error, just failed
done(null, false);
}
}
} catch (e) {
debug(e.stack);
}
client.close();
}());
}
Here is the Auth route the coder I hired wrote that I am having trouble deciphering how to pass in new data to the user model.
// add logic to check if the user is admin
const isAdmin = false;
// user data collected here. If you want to add an "isAdmin" property, this is the right place
const user = {
email, firstName, lastName, password: passwordHash, isAdmin,
};
// checking if the user already exists
const check = await col.findOne({ email });
if (check) {
req.flash('error', 'The user with this email already exists');
res.redirect('back');
} else {
// the user does not exist, insert a new one and authenticate
const results = await col.insertOne(user);
req.login(results.ops[0], () => {
res.redirect('/');
});
}
This is what related to adding the isAdmin property. In order to use req.user and req.isAuthenticated() you are going to need Passport.js. The user data stored in you session (req.user) is defined by your passport strategy so if you want to use the isAdmin property this way, you are going to need to set it there.