Node.js: Cannot read property 'password' of undefined in route - node.js

I am trying to implement my first user login authentication with jwt. I have a registration endpoint, where I have populated fake data. Now I want to login with the data I have in database. I am testing via Postman, but I have an error which is
[Object: null prototype] {
email: 'fakeEmail#gmail.com\t',
password: '12345678'
}
(node:14781) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'password' of undefined
at /home/me/coding/project/backend/routes/user.js:38:40
at processTicksAndRejections (internal/process/task_queues.js:97:5)
(node:14781) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:14781) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
POST /user/login - - ms - -
Assuming it might be because of bodyparser, i have tried both way
//app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser());
but same error.
Here is my login endpoint
router.post("/login",(req, res) => {
const {email, password } = req.body;
console.log(req.body)
pool
.query("SELECT * FROM users WHERE email = $1 AND password = $2 LIMIT 1", [email, password ])
.then(res => {
const data = res.rows[0];
if ( email && password === data.password) {
const token = jwt.sign({ email: req.body.email }, "mySecretKey", {
expiresIn: "30 day",
});
res.send(token);
} else {
res.sendStatus(401);
}
});
});```

You have a problem in res object try loging res in then block. res.rows[0] seems undefined

My problem was, that I have registration endpoint, where I am using Bcrypt, and I had to Verify in Login endpoint. Therefore I was getting errors.
So, here is my corrected Login endpoint
router.post("/login", (req, res) => {
const { email, password } = req.body;
pool
.query("SELECT * FROM users WHERE email = $1 LIMIT 1", [email])
.then((result) => {
const data = result.rows[0];
if (result.rows.length > 0 && email) {
bcrypt.compare(password, data.password, function (err, result) {
if (result) {
const token = jwt.sign({ email: req.body.email }, "mySecretKey", {
expiresIn: "30 days",
});
res.send(token);
} else {
res.sendStatus(401);
}
});
} else {
res.sendStatus(401);
}
});
});
I hope, it will help someone having similar issue

Related

node.js async multiple await not working for user signup

I am trying to reproduce this code using async/await but I can't figure how to
.then.catch chain/nest
exports.signup = (req, res, next) => {
bcrypt.hash(req.body.password, 10)
.then(hash => {
const user = new User({
email: req.body.email,
password: hash
});
user.save()
.then(() => res.status(201).json({ message: 'Utilisateur créé !' }))
.catch(error => res.status(400).json({ error }));
})
.catch(error => res.status(500).json({ error }));
};
What I came up with trying to use async/await
exports.signup = async (req, res, next) => {
try {
const hash = await bcrypt.hash(req.body.password, 10);
const user = new User({
email: req.body.email,
password: hash
});
console.log(user);
let saveUser = await user.save();
console.log(saveUser);
res.status(201).json({ message: 'Utilisateur créé !'})
} catch (e) {
res.status(500).json({e})
}
};
I am getting the user in my console but the code crashes during user.save() since I don't get anything from console.log(saveUser)
I've been reading that you can stack await functions into one try block, but maybe here it doesn't work since you need
I've tried separating the try/catch, requiring me to initialise hash outside of the try block since i'll be using it in the second try but it's also not working.
After editing according to Nil Alfasir's thoughts:
exports.signup = async (req, res, next) => {
try {
const hash = await bcrypt.hash(req.body.password, 10);
const user = new User({
email: req.body.email,
password: hash
});
console.log(user);
user.save();
return res.status(201).json({ message: 'Utilisateur créé !'})
} catch (e) {
return res.status(500).json({e})
}
};
But I'm getting this in the console
(node:43390) UnhandledPromiseRejectionWarning: MongoError: E11000 duplicate key error collection: myFirstDatabase.users index: username_1 dup key: { username: null }
.
.
.
(node:43390) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:43390) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
Correcting Nir Alfasi on save async
save() IS a async function SAVE ASYNC
so it won't return anything.
If there's an error it can be caught be catch.
A few issues:
user.save() doesn't return any value (according to the first snippet) - and you're trying to save a returned value into saveUser
Nit: please add a return before res.status...
UPDATE
The "update" of the question totally changed it, please avoid from doing that and post a new question in the future.
Sounds like you must provide a username when creating a user because username must be unique, and when you try to create multiple users without a username the DB creates a record with username=null so the first one may create but the second one will fail.

Express login: UnhandledPromiseRejectionWarning: Unhandled promise rejection

Good day developers im trying to trigger a process of login for users in my app, generating a token for security reasons, but for some situation im receiving this error
(node:11088) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async
function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:11088) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
despite of allowing the user to log, but then the token although is created isn't exposed on the login json i generated for app purposes checked from my postman.
Lets say i do start the process first in my folder of token generator, after install jsonwebtoken package
jsonwebtoken generation folder
const jsonwebToken = require("jsonwebtoken");
const generateToken =async (userId) => {
return new Promise((reject, resolve) => {
const tokenPayload = { userId };
jsonwebToken.sign(
tokenPayload,
process.env.TOKEN_SECRET_WORD,
{
expiresIn: "12h",
},
(error, generatedToken) => {
if (error) {
reject("cant generate token");
} else {
resolve(generatedToken);
}
}
);
});
};
module.exports = { generateToken };
Once the process of generate the token is set , on my controller for the loginUser function , i set this
et User = require("../modelos/UserModel");
const { response } = require("express");
const cryptoPass = require("bcryptjs");
const { generateToken } = require("../jsonwebtoken/jsonWebTokenGenerator");//path to the json generator
const loginUser = async (request, response = response) => {
const { userEmail, userPassword } = request.body;
try {
const userInDb = await User.findOne({ userEmail });
if (!userInDb) {
return response.status(400).json({
ok: false,
message: "Not user Found",
});
}
const passwordValid = await cryptoPass.compareSync(
userPassword,
userInDb.userPassword
);
if (!passwordValid) {
return response.status(400).json({
ok: false,
message: "Error in Password",
});
}
const tokenGenerated = generateToken(userInDb.id);//generating the tooken in the process
//in order to add it to the user logged json
//once the response is ok(200)
response.status(200).json({
ok: true,
message: "User Logged",
tokenGenerated,//no token
});
} catch (error) {
response.status(500).json({
ok: false,
message: "Some error happened in login",
});
}
};
module.exports = {
loginUser,
};
But then despite of loggin the user , the token isn't brought in the response and that error shows up:
Is weird but if i use an await when asigning the user id to the method of generate token , and then i trigger all the process, then the login isn't successful, and console loggin the catch of that error brings me the token in fact:
......
const tokenGenerated =await generateToken(userInDb.id);//adding an await
// console.log(tokenGenerated,"controller token");
// console.log(userInDb);
response.status(200).json({
ok: true,
message: "User Logged",
tokenGenerated,
});
} catch (error) {
console.log(error,"Error");//loggin the error in the catch
response.status(500).json({
ok: false,
message: "Some error happened in login",
});
}
and in postman the not successful login
Would be amazing any help on this . Thanks in advance!!
The signature of the callback in new Promise() within generateToken is wrong
You are using
return new Promise((reject, resolve) => {
...
});
but the correct one is
return new Promise((resolve, reject) => {
...
});
ie, you switched the resolve and reject parameter. Thus when in your method you try to call resolve(generatedToken); you are actually rejecting your promise with an error of the generated token.

UnhandledPromiseRejectionWarning on Express JS

I'm creating an endpoint for a user to login. it looks to see if a user has a refresh cookie and if not, generates a pair of auth and refresh tokens.
async login(_, { email }, { req, res }) {
try {
const user = await User.findOne({ where: { email } });
if (!user) {
throw new Error("*** COULDN'T FIND USER WITH EMAIL ", email);
}
const tokenAuth =
jsonwebtoken.sign({ id: user.id, email: user.email }, SECRET_AUTH, { expiresIn: TOKEN_AUTH_EXPIRY });
const tokenRefresh =
jsonwebtoken.sign({ id: user.id, email: user.email }, SECRET_REFRESH, { expiresIn: TOKEN_REFRESH_EXPIRY });
const saveRefreshToken = await Token.create({
hash: tokenRefresh,
user_id: user.id,
})
const tokens = {
tokenAuth,
tokenRefresh
}
res.cookie('tokenAuth', tokenAuth, { httpOnly: true, maxAge: 300000 })
res.cookie('tokenRefresh', tokenRefresh, { httpOnly: true, maxAge: 2592000000 })
res.status(200).send({ data: { message: "Tokens Generated!", tokens, login: true }});
} catch(e) {
console.log('*** Error on /login:', e)
}
}
But I get the following errors
(node:14905) UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:470:11)
at apollo_server_core_1.runHttpQuery.then (/Users/z/server/node_modules/apollo-server-express/src/expressApollo.ts:42:17)
(node:14905) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:14905) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
I'm only sending back one res, so why's it throwing that error?

`UnhandledPromiseRejectionWarning: Unhandled promise rejection` in my node application

For learning Node.js I follow a course where they use a async/await like this:
exports.signup = async (req, res) => {
const userExists = await userExists.findOne({ email: req.body.email });
if (userExists) {
return res.status(403).json({
error: "Email is taken!"
});
} else {
const user = await new User(req.body);
await user.save();
return res.status(200).json({ user });
}
};
But it gives me a UnhandledPromiseRejectionWarning with crashing the application.
(node:10780) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise
which was not handled with .catch(). (rejection id: 1)
(node:10780) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero
exit code.
It seems I didn't handle the error part but I did it with my else block, isn't it working like this?
Any help will be appreciated.
You need to catch any rejected promise from await statements by surrounding it with try/catch.
exports.signup = async (req, res) => {
try {
const userExists = await User.findOne({ email: req.body.email });
if (userExists) {
return res.status(403).json({
error: "Email is taken!"
});
} else {
const user = new User(req.body);
await user.save();
return res.status(200).json({ user });
}
} catch(e) {
// some sort of internal error (probably database issue)
console.log(e);
res.sendStatus(500);
}
};
This also removes the await in await new User(req.body) as await only does something useful when you await a promise and new User() is not asynchronous and does not return a promise so there's no reason to use await with it.
Note, that to avoid a race condition where two separate requests might both find that the user doesn't exist and both requests may try to create one, you need to make sure that your user email is configured in the database as a unique key so you can never get duplicate users for the same email. This is a subtlety in server programming that is important to understand to avoid race conditions.
As #jfriend00 said You need to catch any rejected promise from await statements by surrounding it with try/catch. You get ReferenceError because of using userExists before it creates. I am pretty sure that it should be User as you named your Schema User const user = new User(req.body); Let me know if you have any issue after change the code:
exports.signup = async (req, res) => {
try {
const userExists = await User.findOne({ email: req.body.email }); //I changed it to the Schema name
if (userExists) {
return res.status(403).json({
error: "Email is taken!"
});
} else {
const user = new User(req.body);
await user.save();
return res.status(200).json({ user });
}
} catch(e) {
// some sort of internal error (probably database issue)
console.log(e);
res.sendStatus(500);
}
};

I have an error in my registration routes

During the course of testing if my user's registration route is working fine using postman as a testing machine, it throw an error that I don't know what it means.
I have tried using an async function to catch the error, but it didn't work out
const express = require('express');
const router = express.Router();
// Use to help set a default image for users
const gravatar = require('gravatar');
// Use to encrypt our password from bringing plain text
const bcrypt = require('bcryptjs');
// I add the user model from my model
// So i can be able to check create a new registration
// and also check if email exist
const User = require('../../models/User');
// #route GET api/users/register
// #desc Register user
// #access Public
router.post('/register', (req, res) => {
User.findOne({ email: req.body.email }).then(user => {
if (user) {
errors.email = 'Email already exists';
return res.status(400).json(errors);
} else {
const avatar = gravatar.url(req.body.email, {
s: '200', // Size
r: 'pg', // Rating
d: 'mm' // Default
});
const newUser = new User({
name: req.body.name,
email: req.body.email,
avatar,
password: req.body.password
});
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(newUser.password, salt, (err, hash) => {
if (err) throw err;
newUser.password = hash;
newUser
.save()
.then(user => res.json(user))
.catch(err => console.log(err));
});
});
}
});
});
module.exports = router;
I want the user input on postman should be able to post the form so I can know if the route is actually working fine. And this is the error I got on my console
(node:14164) UnhandledPromiseRejectionWarning: ReferenceError: errors is not defined
at User.findOne.then.user (the working director/name.js:26:7)
at process._tickCallback (internal/process/next_tick.js:68:7)
(node:14164) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:14164) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
Normally we should handle the error in a kind of this way:
User.findOne({ email: req.body.email }).then(user => {
// ...
}).catch(error => {
console.log('error', error)
res.json({error: error})
})

Resources