I tried to implement user authentication in Nodejs - node.js

Tried to implement user authentication, but got stuck
(Tech stack: React, Node, Express, Postgresql)
router.post("/signin", function (req, res) {
User.find({
where: {
name: req.body.username,
},
})
.then((user) => {
if (!user) {
return res.status(401).send({
message: "Authentication failed. User not found.",
});
}
user.comparePassword(req.body.password, (err, isMatch) => {
if (isMatch && !err) {
var token = jwt.sign(
JSON.parse(JSON.stringify(user)),
"nodeauthsecret",
{ expiresIn: 86400 * 30 }
);
jwt.verify(token, "nodeauthsecret", function (err, data) {
console.log(err, data);
});
res.json({ success: true, token: "JWT " + token });
} else {
res.status(401).send({
success: false,
msg: "Authentication failed. Wrong password.",
});
}
});
})
.catch((error) => res.status(400).send(error));
});
It returns 500 Error.
I tried testing using Postman but it returns Error. I reviewed the code many times and the logic looks good to me. Any suggestions?

Nothing seems to be wrong with the code. Can I see your user model

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:

why this error is showing? cant set header after they sent to the client

this is mylogin code : you can see the token from here and the next photo is the auth for token
can anyone explain it please............................................................................................................................
const login = (req, res, next) => {
var username = req.body.username;
var password = req.body.password;
User.findOne({$or: [{email: username}, {phoneNumber: username}]})
.then(user => {
if (user) {
bcrypt.compare(password, user.password, function(err, result){
if (err) {
res.json({
title: 'Server error',
error: err
})
console.log('err');
}if (result){
const maxAge = 24 * 60 * 60
const createToken = jwt.sign({ _id: user._id } , process.env.TOKEN_SECRET, { expiresIn: maxAge });
res.header('auth-token',token);
}else{
return res.status(401).json({
title: 'password wrong',
error: 'invalid credentials'
})
}
})
}
else {
return res.status(401).JSON({
title: 'password wrong',
error: 'invalid credentials'
})
}
})
If you look at the bcrypt.compare callback the res.json is executed twice:
function(err, result) {
if (err) {
res.json({}) // ONE
}
if (result) {
// skipped
} else {
return res.status(401).json({ // TWO
title: 'password wrong',
error: 'invalid credentials'
})
}
}
Add a return statement in the if(err)
Using a linter would help you to avoid these oversight

node js + login API

I am trying to login with API using bcrypt to hash the password
problem when comparing hash with the original password always give me output Auth failed1 while username is correct and password is the same .
thanks in advance
router.post('/login', (req, res, next) => {
const user1 = {
Username: req.body.Username,
Password: req.body.Password
};
var sql = "SELECT * FROM Customer WHERE Username = '" + user1.Username + "'";
db.executeSql(sql, function (data, err) {
if (err) {
httpMsgs.show500(req, res, err);
} else {
if (isEmptyObject(data)) {
return res.status(401).json({
message: 'Auth Failed'
});
} else {
bcrypt.compare(user1.Password, data.Password, (err, result) => {
if (err) {
return res.status(401).json({
message: "Auth failed1"
});
}
if (result) {
return res.status(200).json({
message: "Auth successful"
});
}
res.status(401).json({
message: "Auth failed2"
});
});
}
}
});
});
Here response of query, the data variable contains the array of records in unique user case it will have array of length one.
Put data[0].Password and it should work.
Better approach is the get the user object as the response rather than the array. Because we should not have data[0] in good production code.

How to update token when the user logs in in express js?

I want to update token in user collection when the user logs in. So far, I have tried this.
router.post("/login", (req, res, next) => {
User.find({ email: req.body.email })
.exec()
.then(user => {
if (user.length < 1) {
return res.status(401).json({
message: "Auth failed"
});
}
bcrypt.compare(req.body.password, user[0].password, (err, result) => {
if (err) {
return res.status(401).json({
message: "Auth failed"
});
}
if (result) {
const token2 = jwt.sign(
{
email: user[0].email,iat: Math.floor(Date.now() / 1000) - 30
},
"123",
{
expiresIn: "1h"
}
);
User.update({token : token2 })
.exec()
return res.status(200).json({
message: "Auth successful",
token: token2
});
}
res.status(401).json({
message: "Auth failed"
});
});
})
.catch(err => {
console.log(err);
res.status(500).json({
error: err
});
});
});
here new token is getting generated but it is not being saved in the user collection. I want to update new token in the collection.
Can anyone know where I am missing?
Try Something like:
router.post("/login", async (req, res) => {
try{
const user = await User.find({ email: req.body.email });
if (user.length < 1) {
return res.status(401).json({
message: "Auth failed"
});
}
bcrypt.compare(req.body.password, user[0].password, (err, result) => {
if (err) {
return res.status(401).json({
message: "Auth failed"
});
}
if (result) {
const token2 = jwt.sign(
{
email: user[0].email,iat: Math.floor(Date.now() / 1000) - 30
},
"123",
{
expiresIn: "1h"
}
);
User.update({_id:user[0]._id},{$set:{token : token2 }},{new: true});
return res.status(200).json({
message: "Auth successful",
token: token2
});
}
res.status(401).json({
message: "Auth failed"
});
});
}
catch(err){
res.status(500).json({
error: err
});
}
});
Try below code:
jwt.sign(
{
email: user[0].email,iat: Math.floor(Date.now() / 1000) - 30
},
"123",
{
expiresIn: "1h"
}, function(err, token2) {
User.update({token : token2 }).exec() //Change the query to update
return res.status(200).json({
message: "Auth successful",
token: token2
});
}
);
Let me know if it helps.
Firstly understand why do you need to refresh the token. Once you create the token you can store that token as a session variable in a web, internal storage of your mobile etc...
Instead of refresh of token you can create another token.
In another way you can set timeout for the token. Token will be invalid after that time period.

Login: Unable to authenticate user

I am trying to login but the below code always returning below error though the email and password is correct
Authentication failed! Incorrect Password!
exports.login = (req, res, next) => {
User.findOne({
email: req.body.email
}, (err, user) => {
if (err) throw err;
if (!user) {
res.status(401).json({ authenticated: false, message: 'Email is not registered yet! Please Signup and try Signin' });
} else {
// Check if password matches
user.comparePassword(req.body.password, (err, isMatch) => {
if (!isMatch) return res.status(401).send({ message: 'Authentication failed! Incorrect Password!' });
// Make sure the user has been verified
if (!user.isVerified) return res.status(401).send({ type: 'not-verified', message: 'Your account has not been verified. Please check your email' });
if (isMatch) {
const userInfo = setUserInfo(user);
console.log("userInfo: ", userInfo)
res.status(200).json({
token: `${generateToken(userInfo)}`,
user: userInfo
});
}
});
}
});
};
Any idea what I am doing wrong.

Resources