Strategies are responsible for authenticating requests, which they accomplish byimplementing an authentication mechanism. Authentication mechanisms define howto encode a credential, such as a password or an assertion from an identityprovider (IdP), in a request. They also specify the procedure necessary toverify that credential. If the credential is successfully verified, the requestis authenticated.
There are a wide variety of authentication mechanisms, and a correspondingvariety of strategies. Strategies are distributed in separate packages whichmust be installed, configured, and registered.
Install
Strategies are published to the npm registry, andinstalled using a package manager.
For example, the following command will install passport-local,a package which provides a strategy for authenticating with a username andpassword:
$ npm install passport-local
And the following command will install passport-openidconnect,a package which implements support for OpenID Connect:
$ npm install passport-openidconnect
Developers only need to install the packages which provide authenticationmechanisms required by the application. These packages are then plugged intoPassport. This reduces overall application size by avoiding unnecessarydependencies.
Configure
Once a package has been installed, the strategy needs to be configured. Theconfiguration varies with each authentication mechanism, so strategy-specificdocumentation should be consulted. That being said, there are common patternsthat are encountered across many strategies.
The following code is an example that configures the LocalStrategy
:
var LocalStrategy = require('passport-local');var strategy = 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); }); });});
Verify Function
The LocalStrategy
constructor takes a function as an argument. This functionis known as a verify
function, and is a common pattern in many strategies.When authenticating a request, a strategy parses the credential contained in therequest. A verify
function is then called, which is responsible fordetermining the user to which that credential belongs. This allows data accessto be delegated to the application.
In this particular example, the verify
function is executing a SQL query toobtain a user record from the database and, after verifying the password,yielding the record back to the strategy, thus authenticating the user andestablishing a login session.
Because a verify
function is supplied by the application itself, access topersistent storage is not constrained in any way. The application is free touse any data storage system, including relational databases, graph databases,or document stores, and structure data within that database according to anyschema.
A verify
function is strategy-specific, and the exact arguments it receivesand parameters it yields will depend on the underlying authentication mechanism.For authentication mechanisms involving shared secrets, such as a password, averify
function is responsible for verifying the credential and yielding auser. For mechanisms that provide cryptographic authentication, a verify
function will typically yield a user and a key, the later of which the strategywill use to cryptographically verify the credential.
A verify
function yields under one of three conditions: success, failure, oran error.
If the verify
function finds a user to which the credential belongs, and thatcredential is valid, it calls the callback with the authenticating user:
return cb(null, user);
If the credential does not belong to a known user, or is not valid, the verify
function calls the callback with false
to indicate an authentication failure:
return cb(null, false);
If an error occurs, such as the database not being available, the callback iscalled with an error, in idiomatic Node.js style:
return cb(err);
It is important to distinguish between the two failure cases that can occur.Authentication failures are expected conditions, in which the server isoperating normally, even though invalid credentials are being received from theuser (or a malicious adversary attempting to authenticate as the user). Onlywhen the server is operating abnormally should err
be set, to indicate aninternal error.
Register
With the strategy configured, it is then registered by calling .use()
:
var passport = require('passport');passport.use(strategy);
All strategies have a name which, by convention, corresponds to the packagename according to the pattern passport-{name}
. For instance, theLocalStrategy
configured above is named local
as it is distributed in thepassport-local
package.
Once registered, the strategy can be employed to authenticate a request bypassing the name of the strategy as the first argument to passport.authenticate()
middleware:
app.post('/login/password', passport.authenticate('local', { failureRedirect: '/login', failureMessage: true }), function(req, res) { res.redirect('/~' + req.user.username); });
In cases where there is a naming conflict, or the default name is notsufficiently descriptive, the name can be overridden when registering thestrategy by passing a name as the first argument to .use()
:
var passport = require('passport');passport.use('password', strategy);
That name is then specified to passport.authenticate()
middleware:
app.post('/login/password', passport.authenticate('password', { failureRedirect: '/login', failureMessage: true }), function(req, res) { res.redirect('/~' + req.user.username); });
For brevity, strategies are often configured and registered in a singlestatement:
var passport = require('passport');var LocalStrategy = require('passport-local');passport.use(new LocalStrategy(function verify(username, password, cb) { // ...});