I'm using Node, Express, & Mongoose trying to get this POST request to work using Postman but it keeps giving me the 500 status error. I also tried posting with just the username & instead of giving me the expected 400 status error it just gave me a 500 error again.
const jwt = require('jsonwebtoken')
const bcrypt = require('bcrypt')
const User = require('../models/userModel');
const registerUser = async (req, res) => {
try {
//get the username & password from the req.body
const { username, password } = req.body;
//check if the username is unique
const uniqueCheck = await User.findOne(username);
if (uniqueCheck) {
res.status(403).json('Username already exists');
}
//hash password
const salt = await bcrypt.genSalt(10);
const hash = await bcrypt.hash(password, salt);
//check all fields are filled
if (!username || !password) {
res.status(400).json('Please fill in all fields')
} else {
//create user with username & password that is assigned to the hash version of it
const user = await User.create(username, { password: hash });
res.status(201).json(user);
}
} catch (error) {
res.status(500).json({ error: 'Problem registering user' });
}
}
As already I told you in the comment, you should ad a console.error statement in the catch block to better understand where is the problem.
Also, if the first if is matched, a response is sent to the client but the code execution will countinue, triyng to repliyng again to the client and giving you another error. You should return in the first if block to avoid it.
Check the following solution with comments on relevant edits
const jwt = require('jsonwebtoken')
const bcrypt = require('bcrypt')
const User = require('../models/userModel');
const registerUser = async (req, res) => {
try {
//get the username & password from the req.body
const { username, password } = req.body;
//check if the username is unique
const uniqueCheck = await User.findOne(username);
if (uniqueCheck) {
return res.status(403).json('Username already exists'); // --> !!! add a return statement here
}
//hash password
const salt = await bcrypt.genSalt(10);
const hash = await bcrypt.hash(password, salt);
//check all fields are filled
if (!username || !password) {
res.status(400).json('Please fill in all fields')
} else {
//create user with username & password that is assigned to the hash version of it
const user = await User.create(username, { password: hash });
res.status(201).json(user);
}
} catch (error) {
console.error(error) // --> !!! log errors here
res.status(500).json({ error: 'Problem registering user' });
}
}
Related
I'm currently in the process of adding authentication to my app using the MERN stack.
I've managed to add the register functionality for the backend, but I'm struggling with the login function. Despite the user existing in the database, when I test it out in Postman I get an error every time. I tried to just find the user and not validate anything, but that also throws an error, which is confusing since the email definitely exists in the database.
Here's the loginUser and registerUser functions:
const jwt = require('jsonwebtoken');
const bcrypt = require ('bcryptjs')
const asyncHandler = require('express-async-handler')
let User = require('../models/user.model')
const registerUser = asyncHandler(async (req, res) => {
const {name, email, password} = req.body
//validate
if(!name || !email || !password) {
res.status(400)
throw new Error("Please add all fields")
}
const userExists = await User.findOne({email})
if(userExists){
res.status(400)
throw new Error("User already exists")
}
//hash password
const salt = await bcrypt.genSalt(10)
const hashedPassword = await bcrypt.hash(password, salt)
//create new user
const user = await User.create({
name : name,
email : email,
password : hashedPassword
})
if (user){
res.status(201).json({
_id: user.id,
name: user.name,
email: user.email
})
} else {
res.status(400)
throw new Error("Invalid user data")
}
})
const loginUser = asyncHandler(async (req, res) => {
const { email, password } = req.body
// Check for user email
const user = await User.findOne({ email })
if (user && (await bcrypt.compare(password, user.password))) {
res.json({
_id: user.id,
name: user.name,
email: user.email
})
} else {
res.status(400)
throw new Error('Invalid credentials')
}
})
const getUser = asyncHandler(async (req, res) => {
res.json("getUser")
})
router.route('/').post(registerUser)
router.route('/login').post(loginUser)
module.exports = router
And the Postman request:
I double checked the spellings and routes, which are all working fine, and I simply can't put my finger on why it isn't finding the User.
Any direction would be appreciated!
I'm creating an authentication system using Node and Mongoose. I have a login user function here:
export const loginUser = async (req, res) => {
try {
const email = req.body.email;
const password = req.body.password;
//const workingUser = await User.findById("xxxxxxxxxxxx");
console.log(await User.findByCredentials(email, password));
const user = await User.findbyCredentials(email, password);
console.log(user);
if (!user) {
return res.status(401).json({ error: "Login failed! Check authentication credentials." });
}
const token = await user.generateAuthToken();
res.status(201).json({ user, token });
} catch (error) {
res.status(400).json({ error: error });
}
};
I always get a 400 error. Console logging 'user' shows nothing. When I substitute my 'findByCredentials' function for the commented out 'findById', the code works perfectly. Also, where I console log 'await User.findByCredentials(email, password)' the user I want is console logged, which makes me think the findByCredentials code is implemented correctly.
Here is the code for that:
// this method searches for a user by email and password
userSchema.statics.findByCredentials = async (email, password) => {
console.log(email);
const user = await User.findOne({ email });
if (!user) {
throw new Error({ error: "Invalid login details" });
}
const isPasswordMatch = await bcrypt.compare(password, user.password);
if (!isPasswordMatch) {
throw new Error({ error: "Invalid login details"});
}
return user;
}
const User = mongoose.model("User", userSchema);
export default User;
Not exactly sure what I'm doing wrong. Thank you
There's a typo in your code (in second line)
const user = await User.findByCredentials(email, password);
findByCredentials not findbyCredentials. See the capital B
The bcrypt.compare returns false always when it compares the result from the DB with the string password.
Hi Dear, I am trying to create a login authentication for my form. I create the user with a hash password and then I am trying to log in but during to compare plain text password and hashed password bcrypt.compare return false.
When I create a hash password and compare it in the same function it works well but if I take the hash password from the DB again it returns false.
const myFunction = async ()=>{
const passwordText = 'abcd123'
const hashedPassword = await bcrypt.hash(passwordText, 10)
console.log(passwordText)
console.log(hashedPassword)
const isMatch = await bcrypt.compare(passwordText, hashedPassword)
console.log(isMatch)
}
myFunction()
Out Put
abcd123
$2b$10$yNuWJBqlV8NjHrmqOfwaSuKDk.rSB9O6KstAmUpS2770GC1Nlyjw.
true
But when I create user with a hash password like this
router.post('/user/signup', async (req, res)=>{
try{
const user = new User(req.body)
const salt = await bcrypt.genSalt(10)
user.password = await bcrypt.hash(user.password, salt)
await user.save().then((user)=>{
res.status(201).send(user)
}).catch((e)=>{
res.send(e)
})
} catch(e){
res.status(500).send()
}
})
and when I compare it in log in route it returns false
router.post("/user/login", async (req, res) => {
const body = req.body;
const user = await User.findOne({ email: body.email });
if (user) {
// check user password with hashed password stored in the database
const validPassword = await bcrypt.compare(body.password, user.password);
if (validPassword) {
res.status(200).json({ message: "Valid password" });
} else {
res.status(400).json({ error: "Invalid Password" });
}
} else {
res.status(401).json({ error: "User does not exist" });
}
});
I tried to create a hash password in user schema like this
userSchema.pre('save', async function(next){
const user = this
if(user.isModified('password')){
user.password = await bcrypt.hash(user.password, 10)
}
console.log('Befor saveing')
next()
})
again it returns false.
I will appreciate any help, thanks.
Update and Solution
Finally, this post solve my problem, everything is working.
When I create a user in the password field I used lowercase: true, and after that, I remove this now bcrypt compare is working I got True return.
I will share my solution, I hope to help you.
LOGIN
exports.ValidateUser = async (req, res, next) => {
const user = await User.findOne({email:req.query.email});
if(user !== null){
const verify_password = await bcrypt.compare(req.query.password,user.password);
if(verify_password){
const token = await generateToken(user);
res.header("x-auth-token",token).send({
token:token
});
}else{
res.status(400).send({message:'Wrong email or password.'});
}
}else{
res.status(404).send({message:"User not found."})
}
}
Create User
exports.createUser = async (req,res,next) => {
const user = new User({first_name: req.body.first_name,
last_name: req.body.last_name,
email: req.body.email,
password: await bcrypt.hash(req.body.password, 10),
roles:req.body.roles});
user.save().then(()=>{
res.status(201).send({message:"User created."})
}).catch((error)=>{
res.status(400).send({error:error});
});
}
I am trying to get a login function going but when I try to compare password with hashed password it always returns false
This is my registerUser function that holds the hashing
const registerUser = async (request, response) => {
const hashedPassword = await bcrypt.hash(request.body.password, 12)
const user = new UserModel({
username: request.body.username,
password: hashedPassword
});
try {
const databaseResponse = await user.save();
response.status(201).send(databaseResponse);
} catch (error) {
response.status(500).send({message: error.message});
}
};
This is the login function that holds the compare
const login = async (request, response) => {
try{
const user = await UserModel.findOne({username: request.body.username})
if(!user) return response.status(403).send('no user with name ' + request.body.username + ' found');
const isPassValidated = await bcrypt.compare(request.body.password, user.password)
if(!isPassValidated) return response.status(403).send('wrong password');
response.status(200).send('yay');
} catch(error){
response.status(500).send({message: error.message});
}
}
When I console.log request.body.password and user.password the hashed string is equal to the unhashed string so it should return true
The hashed string is the same string that is saved in the database
I just found the issue, thank you for your help. in userSchema, password was lowercase:true which caused the issue...
The code looks alright. Do you have multiple users with the same username in your database? The generated hash should be: $2b$12$jgrLYOqnHnJGszlpgo26QuaT29tdxBFguyIttSNOIy/8go1viRrYC
Currently my project takes sign up requests correctly, and stores emails and encrypted passwords into my MongoDB database. However, when I take the same e-mail and password I signed up with, I get an error telling me that my password is incorrect
I have the following sign in request set up:
module.exports.login_post = async (req, res) => {
// shows us the data that was sent.
// console.log(req.body)
// destructure to just get the email and password from the body
const { email, password } = req.body;
console.log('login called')
try {
const user = await User.login(email, password);
// creates and sends a jwt cookie
const token = createToken(user._id);
res.cookie("jwt", token, { httpOnly: true, maxAge: maxAge * 1000 });
res.status(200).json({ user: user._id });
} catch (err) {
const errors = handleErrors(err);
res.status(400).json({ errors });
}
console.log(email, password)
res.send('user login')
};
In this code I reference User.login, which is imported from my User Model
userSchema.statics.login = async function (email, password){
const user = await this.findOne({ email });
if(user){
const auth = await bcrypt.compare(password, user.password)
if(auth){
return user
}
throw Error('incorrect password')
}
throw Error('incorrect email')
}
Right now, I can register a user, but when I turn around and use the same login and password in Postman I get the error "incorrect password " from my User.login function.
At this point, I am not sure what steps I should be taking in problem solving this. Is there a way to console.log the encyrpted version of the password I try to log in with, so I can make sure I have Bcrypt set up to correctly encrypt the user's password?
Edit: My signup code was requested:
module.exports.signup_post = async (req, res) => {
// destructure to just get the email and password from the body
const { eMail, password } = req.body;
// console.log(email, password)
// add a try catch block
try {
const user = await User.create({
eMail,
password,
words: [
]
});
const token = createToken(user._id);
res.cookie("jwt", token, { httpOnly: true, maxAge: maxAge * 1000 });
// (max age is in seconds and this take milliseconds)
res.status(201).json({ user: user._id });
} catch (err) {
console.log(err)
const errors = handleErrors(err);
// console.log(err);
res.status(400).json({ errors });
}
res.send('new signup')
};
2nd Edit: and this is my middleware the fires before I save a new user and encrypts the password
// hash passwords using SALT
userSchema.pre('save', async function (next){
const salt = await bcrypt.genSalt()
this.password = await bcrypt.hash(this.password, salt)
console.log(this.password)
next()
})
Use below code as your password compare you chnage saltRounds with your bcrypt salt rounds it will compare it with password in database
const comparePassword = (hashedPassword, password) => {
return bcrypt.compareSync(password, hashedPassword);
};
let validations = {
comparePassword,
}
module.exports = validations;