Mongo DB .findOne returning null value. This also lead to my login not working - mongodb

My current login route function that use findOne. Currently using findOne with a email being used to searched for inside my database. But since my user always return null my feedback is always Invalid credentials.
const login = asyncHandler(async (req, res) => {
const { email, password } = req.body
// Check for user email
const user = await Staff.findOne({email})
console.log(user);
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')
}
})

Related

Login post with Bcrypt always return false

Bcrypt.compare returns false no matter what
I'm currently working on a login/register feature in NextJS that utilizes bcrypt to hash and compare user passwords. I'm able to register a user with a hashed password, but when attempting to log in with bcrypt.compare(), the comparison always returns false, even when the entered password matches the hashed password.
The issue lies in this line: const isPasswordMatched = await bcrypt.compare(password, user.password);, where the compare() method is used to compare the entered password with the hashed password. Despite the method's implementation, it's not working as expected.
api/auth/[...nextauth].ts for login
const authOptions: NextAuthOptions = {
session: {
strategy: "jwt",
},
providers: [
CredentialsProvider({
async authorize(credentials, req) {
await connectDB();
const { email, password }: Icredential = credentials;
// Find user by email
const user = await User.findOne({ email: email });
if (user === null) {
throw new Error('Cannot find user');
}
// Check if password from input matches with the one from db
// This is the line of the concern
const isPasswordMatched = await bcrypt.compare(password, user.password);
console.log(`Comparing ${password} to ${user.password}`);
console.log("match ?", isPasswordMatched);
// Throw error when it doesn't
if (!isPasswordMatched)
// if (password !== '123')
{
throw new Error('Invalid email or password');
}
// Return authorized user
return user;
},
credentials: undefined
}),
],
};
export default NextAuth(authOptions);
api/register for register
const registerHandler = async (req: NextApiRequest, res: NextApiResponse) => {
if (req.method === "POST") {
try {
const { user: _regiUser } = req.body;
console.log(_regiUser)
//Check if user exists
await connectDB()
const existingUser = await User.findOne({ email: _regiUser.email }).exec();
console.log("existingUser", existingUser);
//Throw error when email is already in use
if (existingUser) {
throw new Error("Email already used");
}
//Password encrypted
const hashedPassword: string = await bcrypt.hashSync( _regiUser.password, 10 );
console.log("_regiUser.password", _regiUser.password, hashedPassword)
console.log(hashedPassword)
//Replace text password with encrypted password
_regiUser.password = hashedPassword;
console.log(_regiUser)
//Add user on database
await User.create(_regiUser)
res.end()
} catch (e: any) {
console.log(e.message)
}
}
};
export default registerHandler;
Login logic was completely correct, but I had
wrong User model like following:
const userSchema = new mongoose.Schema({
email: {
type: String,
required: true,
lowercase: true
},
password: {
type: String,
required: true,
lowercase: true //remove this to make it work
}
});
look at password entity, because I copy pasted from email entity, i had a wrong configuration for password. So hash stored in lowercase and this is the very reason why i got error no matter what. smh...
You're creating your password hashes using the hashSync() method (not async) but trying to run the async .compare() method when logging-in. Check out the examples.
For the comparison, you should be using:
bcrypt.compareSync(myPlaintextPassword, hash);
Otherwise, I recommend using the async/await bcrypt.hash and bcrypt.compare methods. If you want to use await bcrypto.compare(...), create your hash using:
await bcrypt.hash(password, 10);

Why is MongoDB not saving my user (issues with async/await?) - Express, mongoDB, Oauth

I'm using Oauth to allow my users to sign in with their google account. I have successfully created a function which checks if the email is verified and then, depending on if the user is already saved in the data base, just send back the user - or if the user doesn't exsist create a new user.
My console displays the message "Email is verified" and "User not found" so I know it makes it to that part of the code - but it doesn't proceed to create a new user. My suspicions is that is has to do with the async await and that things are perhaps happening in the wrong order. Any thoughts would be much appreciated!
app.post("/googlelogin", (req, res) => {
const { tokenId } = req.body
client.verifyIdToken({
idToken: tokenId,
audience: 'XXXX' // removed for demo
})
.then(async (response) => {
const { email_verified, name, email } = response.payload
console.log(response.payload)
if (email_verified) {
console.log('email is verified')
try {
const user = await User.findOne({ name, email })
if (user) {
console.log('User found!')
return res.json({
success: true,
name: user.name,
email: user.email,
token: user.token,
userID: user._id
})
} else {
console.log('User not found!')
let newUser = await new User({
name,
email
}).save()
return res.json({
success: true,
name: newUser.name,
email: newUser.email,
token: newUser.token,
userID: newUser._id
})
}
} catch (error) {
res.status(400).json({
success: false,
message: "Something went wrong",
error
})
}
} else {
return res.status(400).json({
success: false,
error: "Email not verified",
})
}
})
})
SOLVED.
Found this thread and followed the tip to drop my collection and after this it worked!
MongoError: E11000 duplicate key error collection: tracker-db.users index: username_1 dup key: { username: null }"

findByIdAndUpdate not updating document on MongoDB

I am trying to create an Api that updates my MongoDB before sending a password reset email to the user using nodemailer. Everything works fine except the database update for some reason. I am using findByIdAndUpdate to do the update.
My api starts with
router.put('/forgot',[auth, [check('email', 'Please include a valid email').isEmail()]],async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
const { email } = req.body;
try {
let user = await User.findOne({ email });
if (!user) {
return res.status(400).json({
errors: [
{
msg:
'That email addrss is not recognized. Please try again or register for a new account ',
},
],
});
}
var email_token = crypto.randomBytes(64).toString('hex');
const payload = {
id: user.id,
resetPasswordToken: email_token,
resetPasswordExpires: Date.now() + 3600000,
};
user = await User.findByIdAndUpdate(
user.id,
{ $set: payload },
{ new: true }
);
console.log(user);
res.json(user);
Thank you Joe and Mohammed, Well from Mohammed question i realized i did not define resetPasswordToken and resetPasswordExpires in the User Model. As soon as i did that every thing worked as magic. Thank you so much!

How to pass body to passport-local?

I'm following some video course where they show me how to use Passport for Google OAuth, and at the end they're just like "Welp, now you can use all the strategies! Have fun!"
So I tried to implement passport-local like so:
// passport.js
// ...
passport.use(
new LocalStrategy((username, password, done) => {
User
.findOne({ username, password })
.then(userFromDB => {
if (userFromDB) {
done(null, userFromDB) // No errs so return the user from db
} else {
new User({
username,
password,
})
.save() // Add user to our db
.then(userFromDB => done(null, userFromDB)) // return user from db
}
})
})
)
// ...
// routes.js
// ...
app.post(`/auth/local`,
passport.authenticate(`local`, {
failureRedirect: `/api/v1/current_user`,
}),
(req, res) => res.send(`It worked`)
)
// ...
My question is how does new LocalStrategy((username, password, done) ... get the username and password?
This is an Express server with Mongo.
app.post('/login',
passport.authenticate('local', { failureRedirect: '/login' }),
function(req, res) {
res.redirect('/');
});
here when you hit route /login then passport.authenticate('local'
automatically call function passport.use(new LocalStrategy( .in
route login from front end side you need to send username and password
passport.use(
new LocalStrategy((username, password, done) => {
User
.findOne({ username, password })
.then(userFromDB => {
if (userFromDB) {
done(null, userFromDB) // No errs so return the user from db
} else {
new User({
username,
password,
})
.save() // Add user to our db
.then(userFromDB => done(null, userFromDB)) // return user from db
}
})
})
)

Getting email with mongoose, always undefined

I'm using mongoose in my nodejs/express project.
I have a login form and I want to retrieve the email field, but I always get a "undefined" value.
This is my code:
User.findOne({ email: email, pass: pass }, function(err, user_data){
if (err) return handleError(err);
if(user_data){
req.session.user_id = user_data._id;
req.session.email = user_data.email;
console.log(user_data);
console.log("the email: " + user_data.email);
console.log("the name: " + user_data.name);
res.redirect('/');
}else{
res.redirect('/login');
}
});
The output:
{ _id: 534038aca4198a8fcf0001ac,
name: 'My name',
email: 'myemail#gmail.com',
pass: '098f6bcd4621d373cade4e832627b4f6' }
The email: undefined
The name: My name
What is wrong with the email field ?
Thanks
I had the same error and i solve creating a new object from the response of the mongoose query.
exports.getUser = async (req, res) => {
try {
const user = await User.findOne({email: email, pass: pass})
const userParams = {...user}
const email = userParams._doc.email
console.log(email)
} catch(err) {
console.log(err)
}
}
I don't recommend you to use this method to auth users, please check auth0 or Oauth2.