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('/');
});
});
Related
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.
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.
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
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('/');
});
});
I'm using nodemailer for a forgot password app, the email executes for the forgot password, but when the user resets their password they don't get a confirmation email. not sure why that's not happening.
seems to be throwing an error on the done(err) line. below is the get handler for the reset token
//get handler for reset token
app.post('/reset/:token', function(req, res, next) {
async.waterfall([
function(done) {
User.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.resetPasswordToken = undefined;
user.resetPasswordExpires = undefined;
user.save(function(err) {
req.logIn(user, function(err) {
done(err, user);
});
});
});
},
function (token, user, done) {
var options = {
service: 'Mailgun',
auth: {
user: 'postmaster#Sandboxxxxxxxxxxx.mailgun.org',
pass: 'xxxxxxxxxxxxxx'
}
};
var transporter = nodemailer.createTransport(smtpTransport(options))
var mailOptions = {
to: user.email,
from: 'postmaster#Sandbox65b418bcf76c4a5e909aedb7b6e87b45.mailgun.org',
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('/');
});
});
You're incorrectly calling done function in the first waterwall task. The second task is expected two parameters: token, user and additional callback. But you pass only one parameter: user.
Add token parameter in done function:
...
user.save(function(err) {
req.logIn(user, function(err) {
done(err, token, user); // TODO: initialize token
});
});
....