Getting an Error on Node.js Postgresql user authentication - node.js

I keep getting an eerror when trying to create user auth with express
this is the error
Executing (default): SELECT "id", "companyName", "password", "email", "createdAt", "updatedAt" FROM "Users" AS "User" WHERE "User"."email" = 'testing#testing.com';
Executing (default): INSERT INTO "Users" ("id","companyName","password","email","createdAt","updatedAt") VALUES (DEFAULT,'test','$2a$10$5zE8XFLAo8JxCqEqj7ELC.Zo.tFPINCgW6pf/WkpqrhDPEkTYPFaS','testing#testing','2020-07-10 04:56:43.081 +00:00','2020-07-10 04:56:43.081 +00:00') RETURNING *;
/Users/ThaylieNguyen 1/Desktop/Projects/EntrepreneurCRM/server/controllers/usersController.js:36
if (err) throw err;
^
Error: Illegal arguments: undefined, string
const signup = (req, res) => {
console.log(req.body)
if (!req.body.email || !req.body.password || !req.body.companyName) {
res.status(400).send({ msg: "Please pass the required information." });
} else {
User.findOne({
where: {
email: req.body.email,
},
})
.then((user) => {
if (!user) {
return res
.status(400)
.json({ email: "a user is already registered with that email" });
} else {
const newUser = User.create({
email: req.body.email,
password: req.body.password,
companyName: req.body.companyName
})
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(newUser.password, salt, (err, hash) => {
if (err) throw err;
newUser.password = hash;
const payload = {
id: newUser.id,
email: newUser.email,
companyName: newUser.companyName,
};
newUser
.save()
.then((user) => {
jwt.sign(
payload,
keys.secretOrKey,
{ expiresIn: 3600 },
(err, token) => {
res.json({
success: true,
token: "Bearer " + token,
});
}
);
})
.catch((err) => console.log(err));
});
});
}
});
}
};

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:

how check if user exist in nodejs

I'm making a auth system with nodejs and mongoDB(mongoose) and I get Error:
error: UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at F:\tryMern\index.js:68:13
index.js (important part) :
app.post("/api/auth", (req, res) => {
if (req.body.username && req.body.pass && req.body.status == "new") {
User.find({ username: req.body.username }, (err, users) => {
if (!err) {
if (users.length > 0) {
return res.json({ error: "The username is taken." });
}
}
});
const validReq = validate.validate({
username: req.body.username,
pass: req.body.pass,
});
if (validReq.error) {
return res.json({ error: validReq.error.details[0].message });
}
bcrypt.hash(req.body.pass, 12).then((hashedPass) => {
// console.log(hashedPass);
const user = new User({
username: req.body.username,
password: hashedPass,
});
user.save().then((user) =>
res.json({
status: "OK",
username: user.username,
token: jwt.sign({ _id: user._id }, jwtKey),
})
);
});
return;
}
User.find({ username: req.body.username }, (err, users) => {
if (err) {
console.log(err);
} else {
if (users.length > 0) {
bcrypt.compare(req.body.pass, users[0].password, (err, hash) => {
if (hash) {
return res.json({
validate: true,
username: users[0].username,
token: jwt.sign({ _id: users[0]._id }, jwtKey),
});
} else {
return res.json({ validate: false });
}
});
} else {
return res.json({ validate: false });
}
}
});
});
when I add The username is taken part the error comes ( the part say find user and if its exist say username is taken)
if there is another way to check if user exist please tell or fix this problem
thanks :)
EDIT:
when i try to submit the user with exist username the response is { "error": "The username is taken." } and the error come
I fix this:
app.post("/api/auth", (req, res) => {
if (req.body.username && req.body.pass && req.body.status == "new") {
User.find({ username: req.body.username }, (err, users) => {
if (!err) {
if (users.length > 0) {
res.json({ error: "The username is taken." });
return;
}
const validReq = validate.validate({
username: req.body.username,
pass: req.body.pass,
});
if (validReq.error) {
return res.json({ error: validReq.error.details[0].message });
}
bcrypt.hash(req.body.pass, 12).then((hashedPass) => {
// console.log(hashedPass);
const user = new User({
username: req.body.username,
password: hashedPass,
});
user.save().then((user) =>
res.json({
status: "OK",
username: user.username,
token: jwt.sign({ _id: user._id }, jwtKey),
})
);
});
}
});
return;
}
User.find({ username: req.body.username }, (err, users) => {
if (err) {
console.log(err);
} else {
if (users.length > 0) {
bcrypt.compare(req.body.pass, users[0].password, (err, hash) => {
if (hash) {
return res.json({
validate: true,
username: users[0].username,
token: jwt.sign({ _id: users[0]._id }, jwtKey),
});
} else {
return res.json({ validate: false });
}
});
} else {
return res.json({ validate: false });
}
}
});
});

How to get response from nodejs server

In my application I want to get response from nodejs server. if I enter already registered mail id I want to get "User already exists" message on browser console.log in register.component.ts. How do it?
Many times tried but not able to findout. Please anyone help.
user.js://server
users.post('/register', (req, res) => {
const today = new Date()
const userData = {
first_name: req.body.first_name,
last_name: req.body.last_name,
email: req.body.email,
password: req.body.password,
created: today
}
User.findOne({
email: req.body.email
})
//TODO bcrypt
.then(user => {
if (!user) {
User.create(userData)
.then(user => {
const payload = {
_id: user._id,
first_name: user.first_name,
last_name: user.last_name,
email: user.email
}
let token = jwt.sign(payload, process.env.SECRET_KEY, {
expiresIn: 1440
})
res.json({ token: token })
})
.catch(err => {
res.send('error: ' + err)
})
} else {
res.json({ error: 'User already exists' })
}
})
.catch(err => {
res.send('error: ' + err)
})
})
authentication.service.ts:
public register(user: TokenPayload): Observable<any> {
const base = this.http.post(`/users/register`, user)
const request = base.pipe(
map((data: TokenResponse) => {
if (data.token) {
this.saveToken(data.token)
}
return data;
})
)
return request;
}
register.component.ts:
register() {
this.auth.register(this.credentials).subscribe(
() => {
this.router.navigateByUrl('/profile')
},
err => {
console.error(err); // how to get error message like "User already exits"
}
)
}

How to hash two password simultaneously using bcyrpt?

I am trying to get login page with two passwords. For only one password the code is working perfectly but when I am adding another password it is throwing error "parallel Save Error".
[0] (node:16516) UnhandledPromiseRejectionWarning: ParallelSaveError: Can't save() the same
doc multiple times in parallel. Document: 5e703180c90fbc40848fcfca
[0] (node:16516) 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: 2)
[0] (node:16516) [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 user.js script:
const express = require('express');
const router = express.Router();
const bcrypt = require('bcryptjs');
const config = require('config');
const jwt = require('jsonwebtoken');
const User = require('../../models/User');
router.post('/', (req, res,) => {
const { name, email, password1, password2 } = req.body;
if(!name || !email || !password1 || !password2) {
return res.status(400).json({ msg: 'Please enter all fields' });
}
User.findOne({ email })
.then(user => {
if(user) return res.status(400).json({ msg: 'User already exists' });
const newUser = new User({
name,
email,
password1,
password2
});
// Hash
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(newUser.password1, salt , (err, hash) => {
if(err) throw err;
newUser.password1 = hash;
newUser.save()
.then(user => {
jwt.sign(
{ id: user.id },
config.get('jwtSecret'),
{ expiresIn: 3600 },
(err, token) => {
if(err) throw err;
res.json({
token,
user: {
id: user.id,
name: user.name,
email: user.email
}
});
}
)
});
})
})
// Create salt & hash
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(newUser.password2, salt, (err, hash) => {
if(err) throw err;
newUser.password2 = hash;
newUser.save()
.then(user => {
jwt.sign(
{ id: user.id },
config.get('jwtSecret'),
{ expiresIn: 3600 },
(err, token) => {
if(err) throw err;
res.json({
token,
user: {
id: user.id,
name: user.name,
email: user.email
}
});
}
)
});
})
})
})
});
module.exports = router;
and the following is the code for Authentication.js
const express = require('express');
const router = express.Router();
const bcrypt = require('bcryptjs');
const config = require('config');
const jwt = require('jsonwebtoken');
const auth = require('../../middleware/auth');
// User Model
const User = require('../../models/User');
router.post('/', (req, res) => {
const { email, password1, password2 } = req.body;
// for validation
if(!email || !password1 || !password2) {
return res.status(400).json({ msg: 'Please enter all fields' });
}
// Check if user exists
User.findOne({ email })
.then(user => {
if(!user) return res.status(400).json({ msg: 'User Does not exist' });
// Validation of password
bcrypt.compare(password1, user.password1)
.then(isMatch => {
if(!isMatch) return res.status(400).json({ msg: 'Invalid credentials' });
jwt.sign(
{ id: user.id },
config.get('jwtSecret'),
{ expiresIn: 3600 },
(err, token) => {
if(err) throw err;
res.json({
token,
user: {
id: user.id,
name: user.name,
email: user.email
}
});
}
)
})
bcrypt.compare(password2, user.password2)
.then(isMatch => {
if(!isMatch) return res.status(400).json({ msg: 'Invalid credentials' });
jwt.sign(
{ id: user.id },
config.get('jwtSecret'),
{ expiresIn: 3600 },
(err, token) => {
if(err) throw err;
res.json({
token,
user: {
id: user.id,
name: user.name,
email: user.email
}
});
}
)
})
})
})
router.get('/user', auth, (req, res) => {
User.findById(req.user.id)
.select('-password1, -password2')
.then(user => res.json(user));
});
module.exports = router;
I am getting only password2 as a hashed password.
password1:"ddd"
password2:"$2a$10$PQhBiDtelKoRspAFn7BW0OuI0pnAyDl.DQSag6bBvYdlirBZM/oAq"
what should I need to do to remove these errors?
I got the answer of above problem...
just need to change the following part in user.js. no need to create hash twice.
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(newUser.password1, salt , async (err, hash) => {
bcrypt.hash(newUser.password2, salt, async (err, hash) => {
if(err) throw err;
newUser.password1 = hash;
newUser.password2 = hash;
await newUser.save()
...
...
same need to do in the athentication.js script.
bcrypt.compare(password1, user.password1)
bcrypt.compare(password2, user.password2)
.then(isMatch => {
if(!isMatch) return res.status(400).json({ msg: 'Invalid credentials'
});
jwt.sign(
{ id: user.id },
...
...
I think it's better to write the encrypt password method in the model.js and export it with the User to the route.js or whatever its name for better & clean code so you can use your method as long as you need.

How to validate password in passport js

I want to prevent users who have a password less than 6 chars from being entered into the database, however my current logic is not allowing that. I'm using express-validator.
Despite a password being less than 6 chars, a user is entered into the database. What should i do to prevent a user who has a password less than 6 chars from being entered into the database ?
I'm using knex/bookshelf orm and postgress for the database
routes/users.js
router.post('/register', [
check('password').isLength({ min: 6 }).withMessage('must be at least 6 chars long'),
check('username').custom( value => {
return User.forge({ username: value}).fetch().then( user => {
if(user){
return Promise.reject('Username already in use');
}
})
}),
check('email').custom( value => {
return User.forge({ email: value}).fetch().then( user => {
if(user){
return Promise.reject('Email already in use');
}
})
})
],
(req, res, next) => {
passport.authenticate('register', (err, user, info) => {
if(err){
console.log(err)
}
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(500).send({
error: errors.array()
})
}
if(info !== undefined){
console.log(info.message)
res.status(403).send(info.message)
}else{
req.logIn(user, err => {
const data = {
username: req.body.username.trim(),
password: req.body.password.trim(),
email: req.body.email.trim()
}
// console.log(data);
// debugger;
User.forge({
username: data.username
}).fetch().then( user => {
const token = jwt.sign({ id: user.id }, process.env.JWT_SECRET);
jwt.verify(token, process.env.JWT_SECRET, function(err, data){
console.log(err, data);
})
console.log('user created in db');
res.status(200).send({
message: 'user created',
token: token,
auth: true
});
});
})
}
})(req, res, next);
});
passport.js
passport.use(
'register',
new Local(
{
usernameField: 'username',
passwordField: 'password',
passReqToCallback: true,
session: false,
},
(req, username, password, done) => {
try {
User.forge({username: username}, {email: req.body.email}).fetch().then(user => {
if (user != null) {
console.log('username or email already taken');
return done(null, false, {
message: 'username or email already taken',
});
} else {
bcrypt.hash(password, 12).then(hashedPassword => {
const user = new User({
username: req.body.username,
password: hashedPassword,
email: req.body.email
})
user.save().then( () => {
return done(null, user);
})
});
}
});
} catch (err) {
return done(err);
}
},
),
);
User model
import bookshelf from '../config/bookshelf';
import validator from 'validator';
/**
* Example User Model.
*/
const User = bookshelf.Model.extend({
tableName: 'users',
timestamps: false,
});
export default User;
Your code is checking for validation errors AFTER you create the user.
Code should be:
(req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).send({ error: errors.array() })
}
passport.authenticate('register', (err, user, info) => {
if(err){
console.log(err)
}
...
Also note that you should be responding with a 400 level error code, not 500. 400 is for when the request made was bad (i.e. validation issue), 500 is when the server acts up.

Resources