I am currently working on an API on node.js. I have seen other similar posts but the solution does not work for me. Below are my codes to retrieve user by email and compare the password. I enter the correct credentials but the compare is always returning false. Am I missing out something?
const bcrypt = require('bcrypt');
const saltRounds = 10;
app.post('/auth', function (req, response) {
let query = `select * from users where email = "${req.body.email}"`;
console.warn(req.body.email);
databaseConnector.query(query, (error, result) => {
if (error) {
console.log(error, 'Error occurred with /auth/ API...');
}
if (result.length > 0) {
console.warn(req.body.password, result[0].password);
bcrypt.compare(req.body.password, result[0].password, function (err, res) {
console.warn(res, 'bcryot response')
// if res == true, password matched
// else wrong password
if (res) {
var token = jwt.sign({ userID: result.id }, 'todo-app-super-shared-secret', { expiresIn: '2h' });
response.send({
token: token,
id: result[0].id,
firstName: result[0].firstName
})
}
else {
return response.sendStatus(401);
}
});
}
else {
return response.sendStatus(401);
}
})
});
Related
Am trying to login my admin , i defined the login credentials both in the mongodb and in the .env so here is the code which has a problem.
const Admin = require('../models/admin');
const Voters = require('../models/voters');
const bcrypt = require('bcrypt');
exports.checkCredentials = async (req, res, next) => {
const email = req.body.email;
const password = req.body.password;
Admin.findOne({ email: email }).exec(async (error, adminData) => {
if (error) {
// some error occured
return res.status(400).json({ error });
}
if (adminData) {
// email is correct checking for password
const match = await bcrypt.compare(password, adminData.password);
if (match) {
req.adminID = adminData._id;
next();
} else {
return res.status(200).json({
msg: 'Invalid email/password combination yyy',
});
}
} else {
// no data found for given email
return res.status(200).json({
msg: 'Invalid email/password combination !!!!',
});
}
});
};
exports.verifyVoter = async (req, res, next) => {
let query;
if (req.query.voterID) {
query = {
voterID: req.query.voterID,
};
} else {
query = {
phone: req.body.phone,
};
}
console.log(query);
Voters.findOne(query).exec(async (error, voterData) => {
if (error) {
// some error occured
return res.status(400).json({ error });
}
if (voterData) {
// Voter found
if (voterData.hasRegistered === true) {
return res.status(200).json({
msg: 'Voter already registered',
});
} else {
req.phone = voterData.phone;
req.district = voterData.pinCode;
req._id = voterData._id;
next();
}
} else {
// no data found for given Voter
return res.status(200).json({
msg: 'Invalid VoterID',
});
}
});
};
that code above brings an error but this is how i defined my admin credentials in the .env
ADMIN_EMAIL = bkroland19#gmail.com
ADMIN_PASSWORD =felinho/013
and this is how i defined them in mongodb
{
"email": "bkroland19#gmail.com",
"password": "felinho/013"
}
and this is the resulting error i get yet the email am entering matches those two emails.
Any help please
Am expecting to be allowed to login in when i enter the credentials as they are in the mongodb database
If you store the password in cleartext you don't need bcrypt.compare:
const match = password === adminData.password;
if (match) {
req.adminID = adminData._id;
next();
}
Anyway, it is strongly suggested to encrypt it, you can do it with:
const salt = await bcrypt.genSalt(12);
const encryptedPassword = await bcrypt.hash(password, salt);
const user = await Admin.create({ email, password: encryptedPassword });
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)
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
})
Not sure what I'm doing wrong, other than writing really messy code for a project I'm doing to learn Nodejs.
This used to be an async function/object but decided to get rid of try catch because my code ran twice for some reason I couldn't figure out.
Eliminating the try catch hasn't really stopped it from still running twice I think.
So the question: Why is my results.rows[0].email returning as undefined?
Sometimes it works sometimes it doesn't. I don't know why. Any help would rock.
router.post('/', (req, res, next) => {
const {password, email} = req.body
//var LoginPwd = await bcrypt.hash(password, 5);
const loginPlainPwd = password;
pool.query("SELECT password, id, email FROM companies_admins WHERE email=$1", [email], (err, results) => {
if (err)
{
throw err;
}
const dbemail = results.rows[0].email
const dbPwd = results.rows[0].password
const dbid = JSON.stringify(results.rows[0].id)
console.log('results.rows[0] = ' + results.rows[0])
console.log('loginPlainPwd = ' + loginPlainPwd)
console.log('dbPwd = ' + dbPwd)
//console.log(JSON.stringify(results.rows[0]))
//res.cookie('userId', id)
//res.sendFile(path.join(__dirname, './views/account.html'));
//bcrypt.compare(loginPlainPwd, dbPwd, (err, res) => {
if (loginPlainPwd != dbPwd)
{
console.log("loginPlainPwd != dbPwd")
/////////////////////////////////////////////?SHOULD THIS BE OUTSIE POOL.QUERY??????
console.log('err')
return res.status(401).json({
message: 'Auth failed'
});
}
else if (loginPlainPwd == dbPwd)
{
//token variable signage/creation with user data and expiration (i also included .env)
const token = jwt.sign(
{
email: dbemail,
userId: dbid,
},
process.env.JWT_KEY,
{
expiresIn: "1h"
},
);
console.log("passwords match: token created:" + token)
res.cookie('userId', token,)
console.log('cookie should be sent')
databaseJWTin(err, token, dbemail); // database function to store jwttoken from below to store jwt in database
console.log('databaseJWT function should have fired')
//had to use ../ below because path was going into routes directory for some reason
res.sendFile(path.join(__dirname, '../views/account.html'))
//return res.status(200).json({
// message: "Auth successful",
// token: token
//});
}
//res.sendFile(path.join(__dirname, './views/account.html'))
});
//res.sendFile(path.join(__dirname, './views/account.html'));
})
Please check whether result contains data in it.
router.post('/', (req, res, next) => {
const { password, email } = req.body
//var LoginPwd = await bcrypt.hash(password, 5);
const loginPlainPwd = password;
pool.query("SELECT password, id, email FROM companies_admins WHERE email=$1", [email], (err, results) => {
if (err) {
throw err;
}
if (results && results.length>0) {
const dbemail = results.rows[0].email
const dbPwd = results.rows[0].password
const dbid = JSON.stringify(results.rows[0].id)
console.log('results.rows[0] = ' + results.rows[0])
console.log('loginPlainPwd = ' + loginPlainPwd)
console.log('dbPwd = ' + dbPwd)
//console.log(JSON.stringify(results.rows[0]))
//res.cookie('userId', id)
//res.sendFile(path.join(__dirname, './views/account.html'));
//bcrypt.compare(loginPlainPwd, dbPwd, (err, res) => {
if (loginPlainPwd != dbPwd) {
console.log("loginPlainPwd != dbPwd")
/////////////////////////////////////////////?SHOULD THIS BE OUTSIE POOL.QUERY??????
console.log('err')
return res.status(401).json({
message: 'Auth failed'
});
}
else if (loginPlainPwd == dbPwd) {
//token variable signage/creation with user data and expiration (i also included .env)
const token = jwt.sign(
{
email: dbemail,
userId: dbid,
},
process.env.JWT_KEY,
{
expiresIn: "1h"
},
);
console.log("passwords match: token created:" + token)
res.cookie('userId', token)
console.log('cookie should be sent')
databaseJWTin(err, token, dbemail); // database function to store jwttoken from below to store jwt in database
console.log('databaseJWT function should have fired')
//had to use ../ below because path was going into routes directory for some reason
res.sendFile(path.join(__dirname, '../views/account.html'))
//return res.status(200).json({
// message: "Auth successful",
// token: token
//});
}
//res.sendFile(path.join(__dirname, './views/account.html'))
}
});
//res.sendFile(path.join(__dirname, './views/account.html'));
})
I have this User schema:
email: {
type: String,
required: true
},
name: {
type: String,
required: true
},
password: {
type: String,
required: true
}
When you do a POST (/api/user-add), I want all the fields to be required. But when I do a login (/api/login) then I only need the email and password fields. My problem is, in my login code I eventually get to this function:
staffSchema.methods.generateToken = function(callback) {
var token = jwt.sign(this._id.toHexString(), config.SECRET);
this.token = token;
this.save(function(err, staff) {
if (err) return callback(err);
callback(null, staff);
});
}
And here it thows an error because the name field is required. How do I bypass this. I am looking for something like this I assume:
this.save(function(err, staff) {
if (err) return callback(err);
callback(null, staff);
}).ignoreRequired('name');
When You Login using JWT token this is a basic example to generate token and authenticate user without store token
Note :
Example to authenticate the user without store token in DB
*Login Method
const jwt = require('./jwt');
userCtr.authenticate = (req, res) => {
const {
email, password,
} = req.body;
const query = {
email: email,
};
User.findOne(query)
.then((user) => {
if (!user) {
//return error user not found.
} else {
if (passwordHash.verify(password, user.password)) { // verify password
const token = jwt.getAuthToken({ id: user._id });
const userData = _.omit(user.toObject(), ['password']); // return user data
return res.status(200).json({ token, userData });
}
//return error password not match
}
})
.catch((err) => {
});
};
*jwt.js
const jwt = require('jwt-simple');
const logger = require('./logger');
const jwtUtil = {};
jwtUtil.getAuthToken = (data) => {
return jwt.encode(data, process.env.JwtSecret);
};
jwtUtil.decodeAuthToken = (token) => {
if (token) {
try {
return jwt.decode(token, process.env.JwtSecret);
} catch (err) {
logger.error(err);
return false;
}
}
return false;
};
module.exports = jwtUtil;
*use middleware to prevent another route to access.
userRouter.post('/update-profile', middleware.checkUser, userCtr.updateProfile);
*middleWare.js
middleware.checkUser = (req, res, next) => {
const { headers } = req;
if (_.isEmpty(headers.authorization)) {
//return error
} else {
const decoded = jwt.decodeAuthToken(headers.authorization.replace('Bearer ', ''));
if (decoded) {
User.findOne({ _id: decoded.id })
.then((user) => {
if (user) {
req.user = user;
next();
} else {
//error
}
})
.catch((err) => {
//errror
});
req.user = decoded;
} else {
//error
}
}
};