Username & Password
A username and password is the traditional, and still most widely used, way for
users to authenticate to a website. Support for this mechanism is provided by
the passport-local
package.
Install
To install passport-local
, execute the following command:
$ npm install passport-local
Configure
The following code is an example that configures and registers the
LocalStrategy
:
var passport = require('passport');
var LocalStrategy = require('passport-local');
var crypto = require('crypto');
passport.use(new LocalStrategy(function verify(username, password, cb) {
db.get('SELECT * FROM users WHERE username = ?', [ username ], function(err, user) {
if (err) { return cb(err); }
if (!user) { return cb(null, false, { message: 'Incorrect username or password.' }); }
crypto.pbkdf2(password, user.salt, 310000, 32, 'sha256', function(err, hashedPassword) {
if (err) { return cb(err); }
if (!crypto.timingSafeEqual(user.hashed_password, hashedPassword)) {
return cb(null, false, { message: 'Incorrect username or password.' });
}
return cb(null, user);
});
});
});
The LocalStrategy
constructor takes a verify
function as an argument, which
accepts username
and password
as arguments. When authenticating a request,
the strategy parses a username and password, which are submitted via an HTML
form to the web application. The strategy then calls the verify
function with
those credentials.
The verify
function is responsible for determining the user to which the
username belongs, as well as verifying the password. Because the verify
function is supplied by the application, the application is free to use a
database and schema of its choosing. The example above illustrates usage of a
SQL database.
Similarly, the application is free to determine its password storage format. The example above illustrates usage of PBKDF2 when comparing the user-supplied password with the hashed password stored in the database.
In case of authentication failure, the verify
callback supplies a message, via
the message
option, describing why authentication failed. This will be
displayed to the user when they are re-prompted to sign in, informing them of
what went wrong.
Prompt
The user is prompted to sign in with their username and password by rendering a form. This is accomplished by defining a route:
app.get('/login',
function(req, res, next) {
res.render('login');
});
The following form is an example which uses best practices:
<form action="/login/password" method="post">
<div>
<label for="username">Username</label>
<input id="username" name="username" type="text" autocomplete="username" required />
</div>
<div>
<label for="current-password">Password</label>
<input id="current-password" name="password" type="password" autocomplete="current-password" required />
</div>
<div>
<button type="submit">Sign in</button>
</div>
</form>
Authenticate
When the user submits the form, it is processed by a route that authenticates the user using the username and password they entered.
app.post('/login/password',
passport.authenticate('local', { failureRedirect: '/login', failureMessage: true }),
function(req, res) {
res.redirect('/~' + req.user.username);
});
If authentication succeeds, passport.authenticate()
middleware calls the next
function in the stack. In this example, the function is redirecting the
authenticated user to their profile page.
When authentication fails, the user is re-prompted to sign in and informed that
their initial attempt was not successful. This is accomplished by using the
failureRedirect
option, which will redirect the user to the login page, along
with the failureMessage
option which will add the message to
req.session.messages
.