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 });
}
}
});
});
Related
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:
I am very new to both nodeJS and React, and am currently trying to get my head around user authentication. I am able to register new users and login to my backend via postman/rapid api, but cannot login correctly via my react front end. Code below:
Front End Requests
import axios from 'axios'
import {AuthModel, UserModel} from './_models'
const API_URL = process.env.REACT_APP_API_URL
export const GET_USER_BY_ACCESSTOKEN_URL = `${API_URL}/auth/signin`
export const LOGIN_URL = `${API_URL}/auth/signin`
export const REGISTER_URL = `${API_URL}/auth/signup`
export const REQUEST_PASSWORD_URL = `${API_URL}/forgot_password`
// Server should return AuthModel
export function login(email: string, password: string) {
return axios.post<AuthModel>(LOGIN_URL, {
email,
password,
})
}
// Server should return AuthModel
export function register(
email: string,
firstname: string,
lastname: string,
password: string,
password_confirmation: string
) {
return axios.post(REGISTER_URL, {
email,
firstname: firstname,
lastname: lastname,
password,
password_confirmation,
})
}
// Server should return object => { result: boolean } (Is Email in DB)
export function requestPassword(email: string) {
return axios.post<{result: boolean}>(REQUEST_PASSWORD_URL, {
email,
})
}
export function getUserByToken(token: string) {
return axios.post<UserModel>(GET_USER_BY_ACCESSTOKEN_URL, {
api_token: token,
})
}
Backend:
const jwt = require("jsonwebtoken");
const config = require("../config/auth.config.js");
const db = require("../models");
const User = db.user;
const Role = db.role;
verifyToken = (req, res, next) => {
let token = req.session.token;
if (!token) {
return res.status(403).send({ message: "No token provided!" });
}
jwt.verify(token, config.secret, (err, decoded) => {
if (err) {
return res.status(401).send({ message: "Unauthorized!" });
}
req.userId = decoded.id;
next();
});
};
isAdmin = (req, res, next) => {
User.findById(req.userId).exec((err, user) => {
if (err) {
res.status(500).send({ message: err });
return;
}
Role.find(
{
_id: { $in: user.roles },
},
(err, roles) => {
if (err) {
res.status(500).send({ message: err });
return;
}
for (let i = 0; i < roles.length; i++) {
if (roles[i].name === "admin") {
next();
return;
}
}
res.status(403).send({ message: "Require Admin Role!" });
return;
}
);
});
};
isModerator = (req, res, next) => {
User.findById(req.userId).exec((err, user) => {
if (err) {
res.status(500).send({ message: err });
return;
}
Role.find(
{
_id: { $in: user.roles },
},
(err, roles) => {
if (err) {
res.status(500).send({ message: err });
return;
}
for (let i = 0; i < roles.length; i++) {
if (roles[i].name === "moderator") {
next();
return;
}
}
res.status(403).send({ message: "Require Moderator Role!" });
return;
}
);
});
};
const authJwt = {
verifyToken,
isAdmin,
isModerator,
};
module.exports = authJwt;
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.email,
firstname: req.body.firstname,
lastname: req.body.lastname,
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,data) => {
if (err) {
res.status(500).send({ message: err });
return;
}
res.send({message: "User 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,data) => {
if (err) {
res.status(500).send({ message: err });
return;
}
var token = jwt.sign({ id: data._id }, config.secret, {
expiresIn: 86400, // 24 hours
});
var authorities = [];
// This is what I mean
req.session.token = token;
res.status(200).send({
id: user._id,
username: user.username,
firstname: user.firstname,
lastname: user.lastname,
email: user.email,
});
//res.send({message: "User registered successfully? No 2"});
});
});
}
});
};
exports.signin = (req, res) => {
User.findOne({
username: req.body.email,
})
.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,
firstname: user.firstname,
lastname: user.lastname,
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);
}
};
exports.allAccess = (req, res) => {
res.status(200).send("Public Content.");
};
exports.userBoard = (req, res) => {
res.status(200).send("User Content.");
};
exports.adminBoard = (req, res) => {
res.status(200).send("Admin Content.");
};
exports.moderatorBoard = (req, res) => {
res.status(200).send("Moderator Content.");
};
Any guidance would be greatly appreciated!
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));
});
});
}
});
}
};
app.post('/sign-up', function (req, res) {
let emailValid = validator.validate(req.body.email);
let consent = req.body.consent ? true:false
if(emailValid && consent) {
const user = new UserModel({
name: req.body.firstName,
surname: req.body.surname,
email: req.body.email
})
UserModel.find({'email': req.body.email}, function(notFound, found) {
if(notFound) {
user.save().then(item => {
console.log('Saved successfully!');
res.render('submitSuccess', {data: req.body});
}).catch(err => {
res.status(400).render('404');
})
} else if(found) {
console.log('Exists');
res.status(404).render('submitSuccess', {data:req.body});
}
else {
res.status(404).render('404');
}
});
}
});
The intended functionality here is that if someone submits an email to the database that already exists, it does not then save a duplicate. However, it seems that found is returning true everytime, therefore nothing is getting saved.
Run this code:
app.post('/sign-up', function (req, res) {
let emailValid = validator.validate(req.body.email);
let consent = req.body.consent ? true : false
if (emailValid && consent) {
const user = new UserModel({
name: req.body.firstName,
surname: req.body.surname,
email: req.body.email
})
UserModel.find({ 'email': req.body.email }, function (err, found) {
if (err) {
console.error(err);
res.status(500).end();
return;
}
if (found.length == 0) {
user.save().then(item => {
console.log('Saved successfully!');
res.render('submitSuccess', { data: req.body });
}).catch(err => {
res.status(400).render('404');
})
} else {
console.log('Exists');
res.status(404).render('submitSuccess', { data: req.body });
}
});
}
});
What's in the err?
I'm using JWT with Passport for authentication in my app, but I don't know how to change the password.
This is my login function:
function login(req, res, next) {
const userObj = {
email: req.body.email,
userType: req.body.userType
};
UserSchema.findOneAsync(userObj, '+password')
.then((user) => {
if (!user) {
const err = new APIError('User not found with the given email id', httpStatus.NOT_FOUND);
return next(err);
} else {
user.comparePassword(req.body.password, (passwordError, isMatch) => {
if (passwordError || !isMatch) {
const err = new APIError('Incorrect password', httpStatus.UNAUTHORIZED);
return next(err);
}
user.loginStatus = true;
user.gpsLoc = [19.02172902354515, 72.85368273308545];
const token = jwt.sign(user, config.jwtSecret);
UserSchema.findOneAndUpdateAsync({ _id: user._id }, { $set: user }, { new: true })
.then((updatedUser) => {
const returnObj = {
success: true,
message: 'user successfully logged in',
data: {
jwtAccessToken: `JWT ${token}`,
user: updatedUser
}
};
res.json(returnObj);
})
.error((err123) => {
const err = new APIError(`error in updating user details while login ${err123}`, httpStatus.INTERNAL_SERVER_ERROR);
next(err);
});
});
}
})
.error((e) => {
const err = new APIError(`erro while finding user ${e}`, httpStatus.INTERNAL_SERVER_ERROR);
next(err);
});
}
my user DB is like this.
import Promise from 'bluebird';
import mongoose from 'mongoose';
import httpStatus from 'http-status';
import APIError from '../helpers/APIError';
import bcrypt from 'bcrypt';
const UserSchema = new mongoose.Schema({
fname: { type: String, default: null },
lname: { type: String, default: null },
email: { type: String, required: true, unique: true },
password: { type: String, required: true, select: false },
});
UserSchema.pre('save', function userSchemaPre(next) {
const user = this;
if (this.isModified('password') || this.isNew) {
bcrypt.genSalt(10, (err, salt) => {
if (err) {
return next(err);
}
bcrypt.hash(user.password, salt, (hashErr, hash) => {
if (hashErr) {
return next(hashErr);
}
user.password = hash;
next();
});
});
} else {
return next();
}
});
UserSchema.methods.comparePassword = function comparePassword(pw, cb) {
const that = this;
bcrypt.compare(pw, that.password, (err, isMatch) => {
if (err) {
return cb(err);
}
cb(null, isMatch);
});
};
I have made another function for reset password and matching checked old password is valid like login function, now I want to update new passport in DB. how will I do that?
Thanks a lot
I'm not sure what you're looking for here, but a changePassword function is just a simple update on UserSchema. Here is a sample:
function changePassword(req, res, next) {
// Init Variables
var passwordDetails = req.body;
if (req.user) {
if (passwordDetails.newPassword) {
UserSchema.findById(req.user.id, function (err, user) {
if (!err && user) {
if (user.authenticate(passwordDetails.currentPassword)) {
if (passwordDetails.newPassword === passwordDetails.verifyPassword) {
user.password = passwordDetails.newPassword;
user.save(function (err) {
if (err) {
return res.status(422).send({
message: errorHandler.getErrorMessage(err)
});
} else {
req.login(user, function (err) {
if (err) {
res.status(400).send(err);
} else {
res.send({
message: 'Password changed successfully'
});
}
});
}
});
} else {
res.status(422).send({
message: 'Passwords do not match'
});
}
} else {
res.status(422).send({
message: 'Current password is incorrect'
});
}
} else {
res.status(400).send({
message: 'User is not found'
});
}
});
} else {
res.status(422).send({
message: 'Please provide a new password'
});
}
} else {
res.status(401).send({
message: 'User is not signed in'
});
}
};
Hope this helps!
You dont have to write any methods in schema. You can directly use ChangePassword function with schema like this
user.changePassword(req.body.oldpassword, req.body.newpassword, function(err)
{