UnhandledPromiseRejectionWarning on Express JS - node.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?

Related

Error: data and hash must be strings in login

I checked my code with postman and it gives this error
(node:6548) UnhandledPromiseRejectionWarning: Error: data and hash must be strings
at Object.compareSync (H:\Chale\Angular Projects\mean-mysql-login-reg\node_modules\bcrypt\bcrypt.js:170:15)
at H:\Chale\Angular Projects\mean-mysql-login-reg\routes\Users.js:58:19
at processTicksAndRejections (internal/process/task_queues.js:97:5)
(node:6548) 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:6548) [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.
This is my code
routes/Users.js
const express = require('express');
const users = express.Router();
const cors = require('cors');
const jwt = require('jsonwebtoken');
const bcrypt = require("bcrypt");
const User = require('../model/User');
users.use(cors());
process.env.SECRET_KEY = 'secret';
//register
users.post('/register', (req,res) => {
const userData = {
first_name : req.body.first_name,
last_name : req.body.last_name,
email : req.body.email,
password: req.body.password
}
User.findOne({
where: {
email: req.body.email
}
})
.then(user => {
if(user){
const hash = bcrypt.hashSync(userData.password, 10)
userData.password = hash
User.create(userData)
.then( user => {
let token = jwt.sign(user.dataValues, process.env.SECRET_KEY,{
expiresIn:1440
})
res.json({ token : token })
})
.catch( err=>{
res.send('error 50555' + error)
})
}else{
res.json({ error:'User already exists!' })
}
})
.catch(err=>{
res.send('error:' + err)
})
})
//login- ***Error is somewhere here in login section***
users.post('/login1', (req, res) => {
User.findOne({
where: {
email : req.body.email
}
})
.then(user => {
if(bcrypt.compareSync(" " + req.body.password, user.password)) {
let token = jwt.sign(user.dataValues, process.env.SECRET_KEY, {
expiresIn: 1440
})
res.json({ token: token })
}else{
res.send('User does not exist!')
}
})
})
module.exports = users
model/User.js
const Sequelize = require('sequelize')
const db = require('../database/db.js')
module.exports = db.sequelize.define(
'user',
{
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
first_name: {
type: Sequelize.STRING
},
last_name: {
type: Sequelize.STRING
},
email: {
type: Sequelize.STRING
},
password: {
type: Sequelize.STRING
}
},
{
timestamps: false
}
)
What is the exact error in this code?
Happy, if someone can help me.
I am new to bcrypt and hash.

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.

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

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

Node JS TypeError: Secret must be a string or buffer

I'm using JWT's for authentication for a user login, but I always get following errors when I want to make a POST on /auth route.
(node:3385) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): TypeError: secret must be a string or buffer
(node:3385) 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.
Here is my code
app.post('/auth', function (req, res, next) {
var username = req.body.username;
var password = req.body.password;
User.findOne({
where: {username: username}
}).then(function (user) {
if(user){
bcrypt.compare(req.body.password, user.password).then(function (passcheck) {
if(passcheck){
var jwtUser = {
username: user.username,
name: user.name,
score: user.score,
accesslevel: "all"
};
var token = jwt.sign(jwtUser, app.get('superSecretString'), {
expiresIn: 1440 //expires in 24 hours
});
//callback(token);
res.json({
success: true,
message: 'HereĀ“s your token.',
token: token
});
/*
var resp = {success: true, message: 'Heres your token.', token: token};
response.write(JSON.stringify(resp));
*/
}else{
res.status(401).json({
success: false,
message: 'Authentification failed. Password or Username wrong'
});
}
});
}else{
res.status(401).json({
success: false,
message: 'Authentification failed.'
});
}
}).catch(next);
});
Thanks for answers.
The problem is you are not declared secret in config file.
you can do it in another way
const token = jwt.sign(user, '123456', {
expiresIn: 60 * 24 // expires in 24 hours
});
remove app.get('superSecretString') and add '123456'
const token = jwt.sign(
{ email: fetchedUser.email, userId: fetchedUser._id },
"secret_this_should_be_longer",
{ expiresIn: "1h" }
);

Unhandled promise rejection - Error: Can't set headers after they are sent

I am new to node, and I have a simple situation, where I am posting to an endpoint on a node/express app. The issue is that I get:
POST /api/v2/user 500 25.378 ms - 54
(node:19024) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): Error: Can't set headers after they are sent.
(node:19024) 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.
The relevant code that I have which is generating this is:
router.post('/', (req, res, next) => {
return authHelpers.createUser(req, res)
.then((user) => {
return localAuth.encodeToken(user[0]);
})
.then((token) => {
res.status(201).json({
status: 'success',
message: 'User Created',
token: token
});
})
.catch((err) => {
res.status(500).json({
status: 'error'
});
});
});
and then:
function createUser(req, res) {
return handleErrors(req)
.then(() => {
const salt = bcrypt.genSaltSync();
const hash = bcrypt.hashSync(req.body.password, salt);
return knex('users')
.insert({
email: req.body.email,
first_name: req.body.first_name,
last_name: req.body.last_name,
username: req.body.username,
password: hash
})
.returning('*');
})
.catch((err) => {
res.status(410).json({
status: err.message
});
});
}
function handleErrors(req) {
return new Promise((resolve, reject) => {
if (req.body.username.length < 6) {
reject({
message: 'Username must be longer than 6 characters'
});
} else if (req.body.password.length < 6) {
reject({
message: 'Password must be longer than 6 characters'
});
} else {
resolve();
}
});
}
I do know that if I remove the res.status(500).json({status: 'error'}); specifically, then the error goes away, but I am not sure if that is proper.
Any clue to what exactly is my error and how to fix?
You are trying to send response twice. First when catching the error
res.status(410).json({
status: err.message
});
And then after catch, promise chain continues the normal route until:
return localAuth.encodeToken(user[0]);
Which fails, because user is undefined and throws an exception.. so error handler is called and you are trying to send response again, but it fails because it has already been sent once
res.status(500).json({
status: 'error'
});
console log which error was thrown in the last part, I'm pretty sure it is something like
TypeError: Cannot read property '0' of undefined

Resources