Password reset link using jwt and nodejs - node.js

This code is not working
router.put('/requestpass',function(req,res){
console.log('inside password');
async.waterfall([
function(done) {
user.findOne({
email: req.query.useremail
}).exec(function(err, user) {
if (user) {
done(err, user);
} else {
done('User not found.');
}
});
},
function(user, done) {
create token
var token= user.generateJwt();
done(err, user, token);
},
// updates user object with new token and expiration date
function(user, token, done) {
user.findOneAndUpdate({ email : req.query.useremail }, { token: token, reset_password_expires: Date.now() + 86400000 }, { upsert: true, new: true }).exec(function(err, new_user) {
if(err){console.log('error hain')}
done(err, token, new_user);
});
},
//configuring email
function(token, user, done) {
ejs.renderFile(__dirname + "../templates/url.ejs", { url: 'http://localhost:3000/auth/reset_password?token=' + token }, function (err, data) {
if (err) {
console.log(err);
} else {
var mainOptions = {
from: 'kapilutkarsh1#gmail.com',
to: "kapilutkarsh1#gmail.com",
subject: 'Password Reset',
html: data
};
console.log("html data >", mainOptions.html);
transporter.sendMail(mainOptions, function (err, info) {
if (err) {
console.log(err);
} else {
console.log('Message sent: ' + info.response);
}
});
}
});
}
], function(err) {
return res.status(422).json({ message: err });
});
});
I have made this function which will send reset password link to the user but it is not working it is showing error on user.findOneandupdate and then in email configuration below is function generating token
userSchema.methods.generateJwt = function() {
var expiry = new Date();
expiry.setDate(expiry.getDate() + 7);
return jwt.sign({
_id: this._id,
email: this.email,
name: this.name,
exp: parseInt(expiry.getTime() / 1000),
}, "MY_SECRET"); //
};
that's how I have configured email
var transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: '**',
pass: '****'
}
});

Try this code
// request to send smtp email containing jwt token in the URL
router.post('/forgot', function(req, res, next){
async.waterfall([
function(done){
Usermodel.findOne({email: req.body.email}, function(err, user){
if(!user){
return res.status(422).send({errors: [{title: 'Invalid email!', detail: 'User does not exist'}]});
}
const token = jwt.sign({
userId: user.id,
username: user.username,
resetPasswordToken: user.resetPasswordToken
}, config.SECRET, { expiresIn: '1h' });
user.resetPasswordToken = token;
user.resetPasswordExpires = Date.now() + 3600000; // 1 hour
user.save(function(err){
done(err, token, user);
});
});
},
function(token, user, done){
const smtpTransport = nodemailer.createTransport({
service: 'Gmail',
auth: {
user: 'XXXX',
pass: 'XXXX'
}
});
const mailOptions = {
to: user.email,
from: 'xxxx#gmail.com',
subject: 'Nodejs password reset',
text: 'You are receiving this email. Please click on the email for password reset ' +
'http://' + req.headers.host + '/reset/' + token + '\n\n' +
'If you did not request this, please ignore this email'
};
smtpTransport.sendMail(mailOptions, function(err){
console.log('mail sent');
done(err, 'done');
});
}
], function(err){
if(err) return next(err);
});
});
// request to get and verify if the token has expired or user is invalid
router.get('/reset/:token', function(req, res){
Usermodel.findOne({resetPasswordToken: req.params.token, resetPasswordExpires: {$gt: Date.now() } }, function(err, user){
if(!user) {
return res.status(422).send({errors: [{title: 'Invalid token!', detail: 'User does not exist'}]});
}
res.json('reset', {token: req.params.token});
});
});
// request to update the password in database if password and confirm password is matching. Also send email to user regarding successful password change
router.post('/reset/:token', function(req, res){
async.waterfall([
function(done) {
Usermodel.findOne({ resetPasswordToken: req.params.token, resetPasswordExpires: { $gt: Date.now() } }, function(err, user){
if(!user){`enter code here`
return res.status(422).send({errors: [{title: 'error', detail: 'Password reset token is invalid or has expired'}]});
}
if(req.body.password === req.body.confirm){
user.setPassword(req.body.password, function(err){
user.resetPasswordToken = undefined;
user.resetPasswordExpires = undefined;
user.save(function(err){
req.logIn(user, function(err) {
done(err, user);
});
});
});
} else {
return res.status(422).send({errors: [{title: 'error', detail: 'Password do not match'}]});
}
});
},
function(user, done){
var smtpTransport = nodemailer.createTransport({
service: 'Gmail',
auth: {
user: 'XXXX',
pass: 'XXXX'
}
});
var mailOptions = {
to: user.email,
from: 'xxxx#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 changed'
};
smtpTransport.sendMail(mailOptions, function(err){
done(err);
});
}
], function(err){
res.redirect('/');
});
});

Related

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.

Reset Password. Token Expire every time in MEAN Stack

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 whenever i click on link given in mail message show "TOken expires"
forgot password node js:-
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_expaire = 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' +
'http://' + req.headers.host + '/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.reset_password= function(req, res,next) {
console.log('Step 1');
User.findOne({
reset_password_token: req.body.token,
reset_password_expires: {$gt: Date.now()}
})
.exec(function(err, user) {
console.log ('step 2')
if (!err && user) {
if (req.body.userPassword === req.body.userConfPassword) {
user.hash_password = bcrypt.hash(req.body.newPassword, 10);
user.reset_password_token = undefined;
user.reset_password_expires = undefined;
user.save(function(err) {
if (err) {
return res.status(422).send({
message: err
});
} else {
var data = {
to: user.userEmail,
from: 'myemail',
subject: 'Password Reset Confirmation',
text: 'Hello,\n\n' +
' - This is a confirmation that the password for your account ' + user.userEmail + ' has just been changed.\n',
};
smtpTransport.sendMail(data, function(err) {
if (!err) {
return res.json({ message: 'Password reset' });
} else {
return done(err);
}
});
}
});
} else {
return res.status(422).send({
message: 'Passwords do not match'
});
}
} else {
return res.status(400).send({
message: 'Password reset token is invalid or has expired.'
});
}
});
};
node Routes
router.post('/forgot_password',forgot_password_Ctrl.forgot_password)
router.get('/reset_password/:token',reset_password_ctrl.reset_password)
Angular ROute
forgotpassword(value) {
return this.http.post(`${this.uri}/forgot_password`, value);
}
resetpassword(token) {
return this.http.post(`${this.uri}/reset_password/${token}`, token);
}
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_expaire: Date,
new_user: String
});
const user = mongoose.model("user", User); //"user" is collections
module.exports= user;

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('/');
});
});

How do I set up reset-password functionality using 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

Resources