I am trying to log in using email and password but if I log in using the right data, it is fine. If I enter any one of the fields wrong then it shows the expected output and crashes instantly and I have to restart the server from npm start. No further API calls can be made afterward if I do not restart the server.
usersRoute:
// Login
router.post('/login', async (req, res) => {
try {
const user = await User.findOne({
email: req.body.email,
});
!user && res.status(401).json('email does not exist in the DB');
const bytes = CryptoJS.AES.decrypt(
user.password,
process.env.SECRET_KEY
);
const originalPassword = bytes.toString(CryptoJS.enc.Utf8);
originalPassword !== req.body.password &&
res.status(401).json('wrong password');
const accessToken = jwt.sign(
{
id: user._id,
},
process.env.SECRET_KEY,
{ expiresIn: '300000' }
);
const { password, ...info } = user._doc;
res.status(200).json({ ...info, accessToken });
} catch (err) {
res.status(500).json(err);
}
});
When you enter a bad credentials, the execution continues to the lines after
!user && res.status(401).json('email does not exist in the DB');
to stop execution of the handler, change this line to:
if(!user) { res.status(401).json('email does not exist in the DB'); return;}
Add a return statement to your res.json calls when you intend to exit the function early. Otherwise, the rest of your code continues to execute and throws an error because the response is already sent.
Your code is throwing an error, because your response is being sent multiple times. Then, your catch is trying to send another response, which throws yet another error.
for password most do originalPassword !== req.body.password && res.status(401).json('wrong password'); to if(Originalpassword !== req.body.password) { res.status(401).json('Wrong credentials password'); return;}
and for email !user && res.status(401).json('email does not exist in the DB');to if(!user) { res.status(401).json('Wrong credentials username'); return;}
Related
Here is my code:
try {
const user = await User.findOne({ email: req.body.email });
!user && res.status(404).json("user not found");
const validPassword = await bcrypt.compare(req.body.password, user.password)
!validPassword && res.status(400).json("wrong password")
res.status(200).json(user)
} catch (err) {
res.status(500).json(err)
}
});
If I use the right credentials there is no problem but
if I type in wrong password or email I get an error stating:
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
and the app crashes, im following a YouTube tutorial by Lama Dev on Node.js Social media API and have the code copied one by one.
You can only send one response for a request.
Here is an example of what you are actually trying to do:
try {
const user = await User.findOne({ email: req.body.email });
if (!user) {
return res.status(404).json("user not found");
}
const validPassword = await bcrypt.compare(req.body.password, user.password)
if(!validPassword) {
return res.status(400).json("wrong password")
}
res.status(200).json(user)
} catch (err) {
res.status(500).json(err)
}
});
Note that the response is returned, which allows exits the function when a response should be sent. You are checking to see IF a user does not exists, and IF they have an invalid password.
I'm trying to create a login system and having some very strange issues.
Page code:
const { email, password } = req.body;
if(!email ||!password) return res.status(400).send("Missing required fields");
let user = await client.fetchUser({ username: email });
if(!user) user = await client.fetchUser({ email });
if(!user) return res.render("login.ejs", {bot:client,message:"Invalid email or password",type:"error"});
const valid = await bcrypt.compare(password, user.account.password);
if(!valid) return res.render("login.ejs", {bot:client,message:"Invalid email or password",type:"error"});
req.session.user = {
username: user.account.username,
password: user.account.password
}
return res.redirect('/dashboard');
When doing
return res.status(200).send("Success");
It works.
I've tried doing await req.session.save() but that does not work either.
Also did some extensive googling and couldn't find an answer.
Please note: this is a POST request.
Sessions are not automatically saved by res.redirect. And req.session.save() does not return a promise but requires a callback function:
req.session.save(function(err) {
if (err) res.status(500).send(err);
else res.redirect("/dashboard");
});
const router = require("express").Router();
const user = require("../models/user");
const cryptoJs = require("crypto-js");
const dotenv = require("dotenv").config();
router.post("/register", async (req, res) => {
const newUser = new user({
username: req.body.username,
password: cryptoJs.AES.encrypt(req.body.password, process.env.pass),
});
try {
const savedUser = await newUser.save();
res.status(201).json(savedUser);
} catch (error) {
res.status(500).json(error);
}
});
router.post("/login", async (req, res) => {
try {
const oneUser = await user.findOne({ username: req.body.username });
if (!oneUser) {
res.status(401).json("Wrong credentials");
}
const hp = cryptoJs.AES.decrypt(oneUser.password, process.env.pass);
const password = hp.toString(cryptoJs.enc.Utf8);
if (password !== req.body.password) {
res.status(401).json("Wrong credentials");
}
res.status(200).json(oneUser);
} catch (error) {
res.sendStatus(500).json(error);
}
});
module.exports = router;
//so, there is the code! everything works fine up to the /login section. when I input the right username and password, it gets me the matching user from the database, but when I input the wrong username and the right password immediately after, it says "wrong credentials which is also fine. But when I input the wrong password after all the previous inputs, it brings this error " Cannot set headers after they are sent to the cliententer code here"
The set header error when will display that you send/return two "res" so use you have to use if-else not if
So the problem is that you send a response to the client, while you already sent a response to the client. When the password is different, you send "Wrong Credentials", but the script will also try to send the oneUser Mongo Object.
To get rid of that, either use an if .. else .. like #Evan proposed, either return the response so you're sure that the script stop there.
The "if/else" solution
if (password !== req.body.password) {
res.status(401).json("Wrong credentials");
}
else {
res.status(200).json(oneUser); // will be sent if the condition before is not completed
}
The "return" solution
if (password !== req.body.password) {
return res.status(401).json("Wrong credentials"); // if the password is different, this will stop the script here
}
res.status(200).json(oneUser);
its better you improve youre block condition like
if (condition){
// do something
}
else {
//do something else
}
OR you can return youre response . it means that when you want to send response return something and exit from the function .
this solution in your code is
router.post("/register", async (req, res) => {
const newUser = new user({
username: req.body.username,
password: cryptoJs.AES.encrypt(req.body.password, process.env.pass),
});
try {
const savedUser = await newUser.save();
return res.status(201).json(savedUser);
} catch (error) {
return res.status(500).json(error);
}
});
router.post("/login", async (req, res) => {
try {
const oneUser = await user.findOne({ username: req.body.username });
if (!oneUser) {
return res.status(401).json("Wrong credentials");
}
const hp = cryptoJs.AES.decrypt(oneUser.password, process.env.pass);
const password = hp.toString(cryptoJs.enc.Utf8);
if (password !== req.body.password) {
return res.status(401).json("Wrong credentials");
}
return res.status(200).json(oneUser);
} catch (error) {
return res.sendStatus(500).json(error);
}
});
I am new to NODEJS / express , and I was following a tutorial to build a small MERN app.
In the initial steps, while setting up a POST route, when sending a POST request with Postman, I am getting this Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
I´ve reading about it, and I somehow understand is because I am calling res.json two times in the same response.
My router is this :
router.post('/login',
async (req, res) => {
try {
const user = await userModel.findOne({email:req.body.email});
!user && res.status(404).send("user not found");
const correctPassword = await bcrypt.compare(req.body.password, user.password);
!correctPassword && res.status(400).json('incorrect password')
res.status(200).json(user); // if not invalid return user
} catch (err) {
console.log(err)
}
})
I tried different solutions i found here (IF & if Else statements, using return ...) without any success.
This very same code (with different variable names) is working flawless in mentioned tutorial.
Any idea how could I solve it?
Thanks in advance.
EDIT : I add the resto of my user Route for completion
´´´
import express from 'express';
const router = express.Router();
import bcrypt from 'bcrypt';
import userModel from '../models/userModel.js'
router.post('/register',
async (req, res) => {
try {
// hash password
const salt = await bcrypt.genSalt(10);
const hashedPassword = await bcrypt.hash(req.body.password, salt)
// Create New User
const newUser = new userModel({
userName: req.body.userName,
email: req.body.email,
password: hashedPassword,
});
// Save New User and return response
const user = await newUser.save();
res.status(200).json(user);
} catch(err){
console.log(err)
}
});
Likely user is falsy or correctPassword evaluates to false, which will send a response of "user not found" or "incorrect password".
However, it continues to execute the rest of your function and eventually executes this line
res.status(200).json(user);
This line will cause the error you've mentioned, as you have already sent a response to the client previously and cannot send another response in the same request-response-cycle.
This should fix the issue:
router.post("/login", async (req, res) => {
try {
const user = await userModel.findOne({ email: req.body.email });
if (!user) {
return res.status(404).send("user not found");
}
const correctPassword = await bcrypt.compare(req.body.password, user.password);
if (!correctPassword) {
return res.status(400).json("incorrect password");
}
return res.status(200).json(user); // if not invalid return user
} catch (err) {
console.log(err);
return res.status(500).send(err.message);
}
});
I'd recommend using ifs here, as it makes the code easier to read. I'd also recommend using return anytime you send a response as it will avoid the issue you ran into.
Error handling in NODE JS
this is my Login Function
router.post('/admin/login', function (req, res) {
User.findOne({ username: req.body.username }, function (err, user) {
if (err) return res.status(500).send('Error on the server.');
if (!user) return res.status(404).send('No user found.');
var passwordIsValid = bcrypt.compareSync(req.body.password, user.password);
if (!passwordIsValid) return res.status(401).send({ auth: false, token: null });
if (req.body.username && req.body.password) {
console.log("enter");
var token = jwt.sign({ id: user._id }, config.secret, {
expiresIn: 86400 // expires in 24 hours
});
res.status(200).send({ auth: true, token: token });
} else {
return res.status(500).send('Error on the server.');
//res.status(500).send("Check Username & Password");
}
});
});
if i forget to enter password the server will be crashed how to handle on this
You need to check to see if the password is being passed before you pass it into the compareSync function.
if (!req.body.password) {
// handle error
return res.status(401).send("Missing or invalid password")
}
If you're doing this you should also check if req.body.username is being provided in the post request. Alternatively for easier method, you can have a try catch wrapped around the query to handle other unexpected errors.
It's better to check in front-end (client side) and also to check for email and password in back-end , there is various libraries to do that , for example i use express-validator lib here is a simple check and of course you can read full docs https://express-validator.github.io/docs/
code sample :
const { check, validationResult, body } = require('express-validator/check');
router.post('/admin/login',[check('email').isEmail(),check('password').isLength({ min: 5 })], (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(422).json({ errors: errors.array() });
}
// the rest of your sing in code here
})
and you can check for name length also this is safer for your back-end always check for validation in front-end and back-end, never trust client side only , do your own validation in the back-end , i hope this answer your question
I was having the same issue with a very similar code.
I replaced this line:
(...)
if (!user) return res.status(404).send('No user found.');
For this:
User.findOne({username : req.body.username},function(err, user){
if(err){
return res.status(401).json({message : err})
};
/* Trying to repair error when username is not on DB */
if(user === null) {
return res.status(401).json({auth : false, token : null, message : "Not Authorised User"});
};
/* Replacement worked */
var isPasswordValid = bcrypt.compareSync(req.body.password, user.password);
Hope it works for you.