An express compatable module for creating RESTful password reset endpoints.
Pass-reset assumes very little about your setup. You use a set of functions when configuring the module that tell pass-reset how to perform the various tasks it needs to, eg. sending emails or looking up users in a database (see the configuration section below for more on the specific config functions).
$ npm install pass-reset
var passReset = require('pass-reset');
// The unit (second param) can be one of the following (or undefined for milliseconds):
// "secs", "mins", "hours", "days", or "weeks"
passReset.expireTimeout(12, 'hours');
var passReset = require('pass-reset');
passReset.lookupUsers(function(login, callback) {
User.find({ username: login }, function(err, users) {
if (err) {return callback(err);}
if (! users.length) {return callback(null, false);}
var user = users[0];
callback(null, {
email: user.email,
users: [{
id: user.id,
name: user.username
}]
});
});
});
var passReset = require('pass-reset');
passReset.setPassword(function(id, password, callback) {
if (password.length < 8) {
return callback(null, false, 'Password must be at least 8 characters');
}
var hash = doHash(password);
var update = { $set: { password: hash } };
User.update({ id: id }, update, { }, function(err) {
if (err) {return callback(err);}
callback(null, true);
});
});
var passReset = require('pass-reset');
var template = handlebars.compile([
'<p>You requested a password reset for the following account(s).</p>',
'<ul>',
'{{#each resets}}',
'<li>{{name}}: <a href="{{url}}">{{url}}</a></li>',
'{{/each}}',
'</ul>'
].join('\n'));
passReset.sendEmail(function(email, resets, callback) {
mailer.send({
to: email,
from: 'noreply@example.com',
subject: 'password reset',
body: template({ resets: resets })
});
callback(null, true);
});
var passReset = require('pass-reset');
var redis = require('redis-url').connect(/* ... */);
passReset.storage.setStore({
create: function(id, token, callback) {
redis.set(token, id, callback);
redis.expire(token, Math.round(passReset.expireTimeout() / 1000));
},
lookup: function(token, callback) {
redis.get(token, callback);
},
destroy: function(token, callback) {
redis.del(token, callback);
}
});
app.post('/password/reset',
passReset.requestResetToken()
);
The requestResetToken
method can also take an object of configuration values. The following values are supported:
- loginParam - The name of the param where the login data (username/email) can be found in
req.body
. - callbackURL - The base URL to direct users to actually perform the reset. This value should contain a
"{token}"
somewhere which will be replaced with the token, eg."/password/reset/{token}"
. - next - By default, when pass-reset is done generating a token and sending it, an empty 200 OK response will be sent. To change this behavior, this value can be given a few different values. If a string is given, it is treated as a redirect, if a function is given, it will be called with the
req
,res
, andnext
parameters, and if any other truthy value is given, thenext
function will simply be called.
app.post('/password/reset',
passReset.requestResetToken({
next: true,
loginParam: 'login',
callbackURL: '/password/reset/{token}',
}),
function(req, res) {
// ...
}
);
app.put('/password/reset',
passReset.resetPassword()
);
The resetPassword
method can also take an object of configuration values. The following values are supported:
- tokenParam/passwordParam/confirmParam - The name of the params where the respective data (token/password/confirm) can be found in
req.body
. - next - By default, after the password is reset, an empty 200 OK response will be sent. To change this behavior, this value can be given a few different values. If a string is given, it is treated as a redirect, if a function is given, it will be called with the
req
,res
, andnext
parameters, and if any other truthy value is given, thenext
function will simply be called.
app.put('/password/reset',
passReset.resetPassword({
next: true,
tokenParam: 'token',
passwordParam: 'password',
confirmParam: 'confirm'
}),
function(req, res) {
// ...
}
);