How to update token when the user logs in in express js? - node.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.

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

I tried to implement user authentication in Nodejs

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

I am not getting any response when my credentials are wrong in catch while calling login API with axios

I am not getting any response while calling login api from nodejs.
I am handling the catch in frontend as well.
How to get Invalid Credentials message from backend API if credentials doesn't matched.
my Backend login API is -
// api to login user
router.post('/login', function (req, res) {
const valid = validator.isEmail(req.body.email)
if (valid == false) {
var message = { "Success": 0, "Message": "Please enter a valid email." };
res.send(message)
}
userObj.findOne({
email: req.body.email
}).then(user => {
if (!user) {
var message = { "Success": 0, "Message": "User does not exists." };
res.send(message)
} else {
// console.log(bcrypt.compare(req.body.password, user.password))
// var message = { "Success": 1, "User": user };
// res.send(message)
bcrypt.compare(req.body.password, user.password)
.then(isMatch => {
if (isMatch) {
const payload = {
name: user.name,
id: user._id,
email: user.email
}
jwt.sign(payload, 'secret', {
expiresIn: 3600
}, (err, token) => {
if (err) console.error('There is some error in token', err);
else {
res.json({
Success: 1,
token: `${token}`
})
}
})
}
else {
res.json({
Success: 0,
Message: 'Invalid Credentials'
})
}
})
}
})
});
my frontend login action code is -
// Login - get user token
export const loginUser = user => dispatch => {
return axios
.post("http://18.207.190.61:4000/login", {
email: user.email,
password: user.password
})
.then(res => {
// Save to localStorage
// Set token to localStorage
localStorage.setItem("usertoken", res.data.token);
// Set token to Auth header
setAuthToken(res.data.token);
// Decode token to get user data
const decoded = jwt_decode(res.data.token);
// Set current user
localStorage.setItem("username", decoded.name);
dispatch(setCurrentUser(decoded));
return res.data;
})
.catch(err => {
return err;
});
};
finally my login component code is -
this.props.loginUser(user).then((res, err) => {
if (res.Success == "0") {
this.setState({
loading: false,
message: res.Message
});
}
});
How can I get message Message: 'Invalid Credentials' from backend API in front end to print.
Please return response with status codes '200' for success and '401' for invalid credentials and try again. Axios recognises the status codes and tells if there is an error.
if(success)
res.status(200).json({
Success: 1,
token: '${token}'
})
else
res.status(401).json({
Success: 0,
Message: 'Invalid Credentials'
})
Try this once.
1.Remove the catch block in your login action code
2. change your login component code to
this.props.loginUser(user).then((res ) => {
if (res.Success == "0") {
this.setState({
loading: false,
message: res.Message
});
}
});

Need of JWT expiresIn field to display on console

how to get expiry time in JWT?
I want to notice every user the expiration time of login token, right now i could display their userId, email id but unable to display expiresIn timings. Please point out where should i edit my code to display expiresIn field.
router.post("/login", (req, res, next) => {
User.find({ username: req.body.username })
.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 token = jwt.sign(
{
username: user[0].username,
email: user[0].email,
userId: user[0]._id,
},
process.env.JWT_KEY,
{
expiresIn: "10h"
}
);
return res.status(200).json({
message: "Auth successful",
token: token,
userId: user[0]._id,
expiresIn: user[0].exp,
});
}
res.status(401).json({
message: "Auth failed"
});
});
})
.catch(err => {
console.log(err);
res.status(500).json({
error: err
});
});
});
This is the output i m getting as of now.
{
"message": "Auth successful",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImRhcnNoYW4iLCJlbWFpbCI6ImRhcnNoYW5hbi4yNEBnbWFpbC5jb20iLCJ1c2VySWQiOiI1YjU3MTcxNmRjODlhYzZiNGUyY2E0MTciLCJpYXQiOjE1Mzg5ODEyOTYsImV4cCI6MTUzONn0.k0PVole653f_pB3CrQLtdUmv7-c00x1irbQph2i2XaE",
"userId": "5b571716dc89ac6b4e2ca417" ,
"email": "darsh4#gmail.com"}
Look like you have not sent the proper expiration response.
let expiration = '10h'
const token = jwt.sign(
{
username: user[0].username,
email: user[0].email,
userId: user[0]._id,
},
process.env.JWT_KEY,
{
expiresIn: expiration
}
);
return res.status(200).json({
message: "Auth successful",
token: token,
userId: user[0]._id,
expiresIn: expiration, //set expiration time
});
Reference link that helps you : here

Resources