How do I set up reset-password functionality using node.js? - node.js

Please I need help writing my forgot-password logic. I have tested what I have using Postman but its not working. I am using nodemailer as the mailserver engine .The entire project is been wired using Angular 4/5 (suggested solutions should please consider this factor). Please help check through and give recommendations/corrections. Thanks.
Here is the code so far--
//forgot password
const transport = require('nodemailer-smtp-transport');
app.get('/forgotPassword', function(req, res){
});
app.post('/forgotPassword', function(req, res, next){
async.waterfall([
function(done) {
crypto.randomBytes(20, function(err, buf) {
const token = buf.toString('hex');
done(err, token);
});
},
function(token, done) {
user.findOne({email: req.body.email }, function(err, user, req) {
if (!user){
console.log ('No account with that email address exists.');
}
user.resetPasswordToken = token;
user.resetPasswordExpires = Date.now() + 3600000; //1 hour
});
},
function(token, user, done){
const smtpTransporter = nodemailer.createTransport({
service: 'Gmail',
auth: {
user: 'preciousegunjobi#gmail.com',
pass: 'Presidoe2011!'
}
});
const mailOptions = {
from: 'preciousegunjobi1#gmail.com', //sender
to: req.body.email,
subject: 'Password Reset Notification',
html: '<h3>You are receiving this because you (or someone else) have requested the reset of the password on your account. ' + '\n' + ' Please click on the following link, or paste into your browser to complete the password reset process. </h3>' +' \n '+ 'http://' + req.headers.host + '/reset/' + token + '\n\n' +
'<h4> If you did not request this, please ignore this email and your password will remain unchanged </h4>'
};
smtpTransporter.sendMail(mailOptions, function(err, req){
console.log('mail sent');
console.log ('success', 'An e-mail has been sent to ' + user.email + 'with further instructions to reset password.');
done(err, 'done');
});
}
], function(err){
if (err) return next(err);
});
});
app.get ('/reset/:token', function(req, res){
user.findOne({ resetPasswordToken: req.params.token, resetPasswordExpires: {$gt: Date.now() } }, function(err, user, req){
if (!user){
console.log ('error', 'Password reset token is invalid or has expired.');
}
// if(req.body.password === req.body.confirm) {
// user.setPassword(req.body.password, function(err, token) {
user.password = req.body.password;
user.resetPasswordToken = undefined;
user.resetPasswordExpires = undefined;
console.log('password' + user.password + 'and the user is' + user)
// )
})
// } else {
//console.log ("error", "Passwords do not match.");
// }
// });
},
function(user, done) {
const smtpTransporter = nodemailer.createTransport({
service: 'Gmail',
auth: {
user: 'preciousegunjobi1#gmail.com',
pass: 'Presidoe2011!'
}
});
const mailOptions = {
to: user.email,
from: 'preciousegunjobi1#gmail.com',
subject: 'Your password has been changed',
text: 'Hello, \n\n' +
'This is a confirmation that the password for your account ' + user.email + ' has just been changed.'
};
smtpTransporter.sendMail(mailOptions, function(err, req) {
console.log ('success', 'Success! Your password has been changed.');
done(err);
});
});
//end of forgot password logic

Related

why findOne () not return any value in mogooDB

why findOne does not return any value. I am trying to find the user with his email address but this function returning null. and I am exit from the function. help me solve this function, actually, this is a password reset post route. I am getting a username but when I reach to user.findOne () its return me null value . and also token undefined, i don't know how to fix, give me some solution
app.post('/check-auth', (req, res, next)=> {
console.log(req.body)
async.waterfall([
function(done) {
crypto.randomBytes(20, function(err, buf) {
var token = buf.toString('hex');
done(err, token);
});
},
async function(token, done) {
const user = await User.findOne({ email: req.body.username });
console.log(user);
if (!user) {
req.flash('error', 'No account with that email address exists.');
return res.redirect('/forget-password');
}
// Do your stuff with the user
user.resetPasswordToken = token;
user.resetPasswordExpires = Date.now() + 3600000; // 1 hour
user.save(function(err) {
done(err, token, user);
});
},
function(token, user, done) {
var smtpTransport = nodemailer.createTransport({
service: 'Gmail',
auth: {
user: 'xyz#gmail.com',
pass: 'jvjvsdjfvjdvjdvdv'
}
});
console.log(user.email)
var mailOptions = {
from: 'passwordreset#demo.com',
to: req.body.username,
subject: 'Node.js Password Reset',
text: 'You are receiving this because you (or someone else) have requested the reset of the password for your account.\n\n' +
'Please click on the following link, or paste this into your browser to complete the process:\n\n' +
'http://' + req.headers.host + '/reset/' + token + '\n\n' +
'If you did not request this, please ignore this email and your password will remain unchanged.\n'
};
smtpTransport.sendMail(mailOptions, function(err) {
req.flash('info', 'An e-mail has been sent to ' + user.email + ' with further instructions.');
done(err, 'done');
});
}
], function(err) {
if (err) return next(err);
res.redirect('/forgot');
});
});
You are mixing async, await with callbacks.
Try that following way.
async function(token, done) {
const user = await User.findOne({ email: req.body.username });
console.log(user);
if (!user) {
req.flash('error', 'No account with that email address exists.');
return res.redirect('/forget-password');
}
// Do your stuff with the user
}
If you want to handle errors then wrap the whole code block inside try and catch.
I hope this will solve your issue.

Nodejs password reset I get an emai and click on the link but the new password does not change. I can only log in with old password

I am 99% done with my password reset application. I get an email for the password reset, but my new password change does not change in my mongodb. I can't log in with new password only old password. What am I doing wrong
router.post('/reset/:token', function(req, res) {
async.waterfall([
function(done) {
Account.findOne({ resetPasswordToken: req.params.token, resetPasswordExpires: { $gt: Date.now() } }, function(err, user) {
if (!user) {
req.flash('error', 'Password reset token is invalid or has expired.');
return res.redirect('back');
}
user.password = req.body.password;
//user.password = hashedPassword;
user.resetPasswordToken = undefined;
user.resetPasswordExpires = undefined;
user.save(function(err) {
req.logIn(user, function(err) {
done(err, user);
});
});
});
},
function(user, done) {
var transporter = nodemailer.createTransport({
service: 'Gmail',
auth:{
user: '',
pass: ''
}
});
var mailOptions = {
to: user.email,
from: '',
subject: 'Your password has been changed',
text: 'Hello,\n\n' +
'This is a confirmation that the password for your account ' + user.email + ' has just been changed.\n'
};
transporter.sendMail(mailOptions, function(err) {
req.flash('success', 'Success! Your password has been changed.');
done(err);
});
}
], function(err) {
res.redirect('/');
});
});
I figured it out. I had to user setPassword function
if(req.body.password === req.body.confirm) {
user.setPassword(req.body.password, function(err) {
Thanks.

Getting an error that token is expired when trying to reset password following click on email link. Using Node js, express and mongoose

I have created a user registration and login. All working fine. Trying to implement password reset. All is working fine up to the point of filling in the new password and confirming same. Then getting an error that token has expired. No idea why. I'm pretty new to coding (a few month) so sincere apologies if I am not posting this properly. Have used the site a lot but it's my first time posting... Any help would be very much appreciated. Thank you.
p.s
I'm including the main js file. I'm not sure if I need to include any of the other files but as they are quite a number, I'll wait to see if anyone asks to see anything else. Thanks again.
//users.js
const express = require('express');
const router = express.Router();
const passport = require('passport');
const bcrypt = require('bcryptjs');
const async = require('async');
const nodemailer = require('nodemailer');
const crypto = require('crypto');
// User model
const User = require('../models/User');
// Login Page
router.get('/login', function(req, res){
res.render('login');
});
// Register Page
router.get('/register', function(req, res){
res.render('register');
});
// Register Handle
router.post('/register', function (req, res){
const { name, email, password, password2 } = req.body;
let errors = [];
// Check required fields
if(!name || !email || !password || !password2) {
errors.push({ msg: 'Please fill in all fields' });
}
// Check passwords match
if(password !== password2) {
errors.push({ msg: 'Passwords do not match' });
};
// Check password length
if(password.length < 6) {
errors.push({ msg: 'Password should be at least 6 characters' });
};
// If there are errors
if(errors.length > 0){
res.render('register', {
errors,
name,
email,
password,
password2
});
} else {
//Validation passed
User.findOne({ email: email })//This is going to return a promise
.then(function (user){
//If User exists
if(user){
errors.push({ msg: 'Email already registered' });
res.render('register', {
errors,
name,
email,
password,
password2
});
} else {
//If email not registered create a new User
const newUser = new User({
name,// es6 instead of 'name: name' and same for below
email,
password
});
// Hash Password
bcrypt.genSalt(10, function(err, salt){
bcrypt.hash(newUser.password, salt, function(err, hash){
if(err) throw err;
//Set password to hashed
newUser.password = hash;
// Save user
newUser.save()
.then(function(user){
req.flash('success_msg', 'You have been successuflly registered and can now log in');
res.redirect('/users/login');
})
.catch(err, function(){
console.log(err);
});
});
});
}
});
}
});
// Login Handle
router.post('/login', function(req, res, next){
passport.authenticate('local', {
successRedirect: '/dashboard',
failureRedirect: '/users/login',
failureFlash: true
})(req, res, next);
});
// Logout Handle
router.get('/logout', function(req, res){
req.logout();
req.flash('success_msg', 'You have been logged out');
res.redirect('/users/login');
});
// Forgot Password Page
router.get('/forgot', function (req, res){
res.render('forgot');
});
// Forgot Password Handle
router.post('/forgot', function(req, res, next) {
async.waterfall([
function(done) {
crypto.randomBytes(20, function(err, buf) {
var token = buf.toString('hex');
done(err, token);
});
},
function(token, done) {
User.findOne({ email: req.body.email }, function(err, user) {
if (!user) {
req.flash('error', 'No account with that email address exists.');
return res.redirect('/users/forgot');
}
user.resetPasswordToken = token;
user.resetPasswordExpires = Date.now() + 3600000; // 1 hour
user.save(function(err) {
done(err, token, user);
});
});
},
function(token, user, done) {
var smtpTransport = nodemailer.createTransport({
service: 'Gmail',
auth: {
user: 'nirshihor#gmail.com',
pass: '<password>'
}
});
var mailOptions = {
to: user.email,
from: 'nirshihor#gmail.com',
subject: 'WSS Password Reset',
text: 'You are receiving this because you (or someone else) have requested the reset of the password for your account.\n\n' +
'Please click on the following link, or paste this into your browser to complete the process:\n\n' +
'http://' + req.headers.host + '/users/reset/' + token + '\n\n' +
'If you did not request this, please ignore this email and your password will remain unchanged.\n'
};
smtpTransport.sendMail(mailOptions, function(err) {
console.log('mail sent');
req.flash('success_mail_sent', 'An e-mail has been sent to ' + user.email + ' with further instructions.');
done(err, 'done');
});
}
], function(err) {
if (err) return next(err);
res.redirect('/users/forgot');
});
});
router.get('/reset/:token', function(req, res) {
User.findOne({ resetPasswordToken: req.params.token, resetPasswordExpires: { $gt: Date.now() } }, function(err, user) {
if (!user) {
req.flash('error_token', 'Password reset token is invalid or has expired.');
return res.redirect('/users/forgot');
}
res.render('reset', {token: req.params.token});
});
});
router.post('/reset/:token', function(req, res) {
async.waterfall([
function(done) {
User.findOne({ resetPasswordToken: req.params.token, resetPasswordExpires: { $gt: Date.now() } }, function(err, user) {
if (!user) {
req.flash('error_token', 'Password reset token is invalid or has expired.');
return res.redirect('back');
}
if(req.body.password === req.body.confirm) {
user.setPassword(req.body.password, function(err) {
user.resetPasswordToken = undefined;
user.resetPasswordExpires = undefined;
//Update user in database
user.save(function(err) {
req.logIn(user, function(err) {
done(err, user);
});
});
})
} else {
req.flash("error_passwords_match", "Passwords do not match.");
return res.redirect('back');
}
});
},
function(user, done) {
var smtpTransport = nodemailer.createTransport({
service: 'Gmail',
auth: {
user: 'nirshihor#gmail.com',
pass: 'N1rSh1hor?#'
}
});
var mailOptions = {
to: user.email,
from: 'nirshihor#mail.com',
subject: 'Your password has been changed',
text: 'Hello,\n\n' +
'This is a confirmation that the password for your account ' + user.email + ' has just been changed.\n'
};
smtpTransport.sendMail(mailOptions, function(err) {
req.flash('success_password_change', 'Success! Your password has been changed.');
done(err);
});
}
], function(err) {
res.redirect('/home');
});
});
module.exports = router;
Managed to sort it. I put together two different tutorials I followed. One was for registering users and logging in, and the other was for resetting password. I failed to implement the hashing process for the password reset as I did in the first tutorial, which caused the problem. Now resolved. If anyone experiencing the same issue requires code sample - happy to supply.

Unable to Save Bcrypt Password in reset Password

i am new in MEAN Stack, working on forgot password and reset password. i complete forgot password front end with Angular 8 and node and express. Mail sent to user email for reset password. but i am unable to save bcrypt password
Forget Password
exports.forgot_password= function(req, res){
async.waterfall([
function(done) {
crypto.randomBytes(20, function(err, buf) {
var token = buf.toString('hex');
done(err, token);
});
},
function(token, done) {
User.findOne({ userEmail: req.body.userEmail }, function(err, user) {
if (!user) {
return res.json({status:false, message:'E-Mail not Found'})
}
console.log('step 1')
user.reset_password_token = token;
user.reset_password_expire = Date.now() + 3600000; // 1 hour
user.save(function(err) {
done(err,token, user);
});
});
},
function(token, user, done) {
console.log('step 2')
var smtpTrans = nodemailer.createTransport({
service: 'Gmail',
auth: {
user: 'myemail',
pass: 'mypass'
}
});
console.log('step 3')
smtpTrans.sendMail({
from: 'myemail',
to:user.userEmail,
subject:'Password Reset',
text:'You are receiving this because you (or someone else) have requested the reset of the password for your account.\n\n' +
'Please click on the following link, or paste this into your browser to complete the process:\n\n' +
'angular URL + '/api/reset_password/' + token + '\n\n' +
'If you did not request this, please ignore this email and your password will remain unchanged.\n',
});
console.log('Email Send');
}
], function(err) {
console.log('this err' + ' ' + err)
});
};
Reset Password
exports.resetpassword= function(req, res,next) {
async.waterfall([
function(done){
User.findOneAndUpdate({
reset_password_token: req.body.token,
reset_password_expire: {$gt: Date.now()}
},function(err, user){
if(user && !err){
console.log('user')
return res.json({status:true, message:'Reset Password'})
}else{
console.log('Token Expire');
return res.json({status:false, message:'Token Invalid of Expire'})
}
},
function(err, user,next){
if (!user && err) {
console.log('User Now found')
return res.json({status:false, message:'User Not found'})
}
user.userPassword = req.body.userPassword;
bcrypt.hash(req.body.userPassword,saltRounds,(hash)=> {
user.userPassword = hash;
})
user.reset_password_token = undefined;
user.reset_password_expire = undefined;
console.log('password is ' + user.userPassword + ' and the user is ' + user)
//Save
user.save(function(err) {
if (err) {
console.log('here')
return res.status(422).send({message: err});
}else{
console.log('here2')
var smtpTrans = nodemailer.createTransport({
service: 'Gmail',
auth: {
user: 'myemail',
pass: 'mypass'
}
});
var data = {
to: user.userEmail,
from: 'myemail',
subject: 'Password Reset Confirmation',
text: 'Hello ' + user.userName +',\n\n' +
' - This is a confirmation that the password for your account ' + user.userEmail + ' has just been changed.\n',
};
smtpTrans.sendMail(data, function(err) {
console.log('Password has been changed')
// req.flash('success', 'Success! Your password has been changed.');
done(err);
});
}
});
});
},
], function(err) {
return res.json({status:true, message:'error'})
});
};
Schema
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const User = new Schema({
userName: String,
userEmail: String,
userPassword: {type: String,required: true, bcrypt: true},
userConfPassword: String,
userPhone: Number,
userExperience: String,
reset_password_token: String,
reset_password_expire: Date,
});
const user = mongoose.model("user", User); //"user" is collections
module.exports= user;
the issue mainly with this:
bcrypt.hash(req.body.userPassword,saltRounds,(hash)=> {
user.userPassword = hash;
})
and its async! try to replace it with:
user.userPassword = bcrypt.hash(req.body.userPassword,saltRounds)
simple example:
let x;
setTimeout(()=>{
x = 400
console.log(x) // 400
},200)
console.log(x) // undefined - this console.log while be executed first (js asynchronous concept)

NodeJS Request Parameter not showing value

I have the following url to reset a password using a token:
http://localhost:xxxx/reset/a513293ba51df393568cebfab178754eb284bb62
I have the following route handler:
router.post('/reset/:token', function(req, res) {...
For some reason my request parameter does not display the value in my route.
req.params.token displays: reset, not a513293ba51df393568cebfab178754eb284bb62
I must be missing something very obvious because all my other pages and routes work fine.
After spending some more time on this I think I might have an idea why my req object is not working. It must be because of the async call. How can I get this to work?
My full route is this:
router.post("/reset/:token", function(req, res) {
async.waterfall([
function(done) {
console.log(req.params.token);
UserModel.findOne({ resetPasswordToken: req.params.token, resetPasswordExpires: { $gt: Date.now() } }, function(err, user) {
if (!user) {
return res.redirect('/login');
}
user.password = req.body.password;
user.resetPasswordToken = undefined;
user.resetPasswordExpires = undefined;
user.save(function(err) {
req.logIn(user, function(err) {
done(err, user);
});
});
});
},
function(user, done) {
var smtpTransport = nodemailer.createTransport({
service: 'SendGrid',
auth: {
user: 'xxx',
pass: 'xxx'
}
});
var mailOptions = {
to: user.email,
from: 'passwordreset#demo.com',
subject: 'Your password has been changed',
text: 'Hello,\n\n' +
'This is a confirmation that the password for your account ' + user.email + ' has just been changed.\n'
};
smtpTransport.sendMail(mailOptions, function(err) {
console.log('Success! Your password has been changed.');
done(err);
});
}
], function(err) {
res.redirect('/');
});
});

Resources