Notify user on `resetPassword`


#1

Hello! I’ve built an application using Meteor user accounts but not accounts UI - doing everything manually.

I’ve got a forgot password link that opens form setup in a modal on the login screen where users can fill out their email address to get password reset instructions. This uses the built in forgotPassword function which successfully sends the email with the token.

Resetting the password has been simple as well using Accounts.onResetPasswordLink and then Accounts.resetPassword. I’ve tested this with a hardcoded newPassword and it’s worked fine. However, I want to generate a random password, set it, and then send a mail to the user with the new password.

While Accounts.resetPassword takes the token, changes the password, and logs the user in. The callback runs before the user is logged in so I can’t get any user details and therefore cannot send the new password mail.

// Client
/* On link click in email */

Accounts.onResetPasswordLink(function(token, callback) {
/* Generate password */

function randomString(length, chars) {
    let result = '';
    for (var i = length; i > 0; --i) result += chars[Math.floor(Math.random() * chars.length)];
    return result;
}

const rString = randomString(32, '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ');

/* Send email with new password */

Meteor.call('sendNewPassword', rString, function(err, result) {
	/* If no error */
	
	if (!err) {
		// Alert user of email and change
		Bert.alert('Password changed. Please check your email for your new password.', 'success');
	}
});

/* Reset password */

Accounts.resetPassword(token, rString, function(err) {
	if (!err) {
		console.log('Done');
	}
});
});

Any help is appreciated!


#2

OK I’ve managed to solve this by digging into the DB a bit and finding where the token is sitting. The token that gets generated is saved to the user entry under services.password.reset.token.

Updated code to find the user via the token:

// Client
/* On link click in email */

Accounts.onResetPasswordLink(function(token, callback) {
/* Generate password */

function randomString(length, chars) {
    let result = '';
    for (var i = length; i > 0; --i) result += chars[Math.floor(Math.random() * chars.length)];
    return result;
}

const rString = randomString(32, '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ');

/* Get user email */

Meteor.call('getEmailFromToken', token, function(err, result) {
	/* Reset password */
	
	Accounts.resetPassword(token, rString, function(err) {
		if (!err) {
			/* Send email with new password */
			
			Meteor.call('sendNewPassword', result, rString, function(err, result) {
				/* If no error */
				
				if (!err) {
					// Alert user of email and change
					Bert.alert('Password changed. Please check your email for your new password.', 'success');
				}
			});
		}
	});
});
});

And then:

// Server
/* Get user email from token */

'getEmailFromToken': function(token) {
	/* Get user email */
	
	const user = Meteor.users.findOne({'services.password.reset.token': token});
	const userEmail = user.emails[0].address;

	return userEmail;
},
/* Send new password */

'sendNewPassword': function(email, password) {
	const returnVal = Email.send({
		to: email,
		from: Meteor.settings.ApplicationEmail,
		subject: 'Application password changed',
		html: 'Hello,<br><br>Your Application password has been changed. Your new password is ' + password
	});

	return returnVal;
}