Protecting Node.js services written with Restify using Passport

I’ve been using Restify to create all my REST endpoints for the various services that I write. Invariably, I need to protect these services end-to-end. For client-facing UI’s I do that with OAuth, but my OAuth proxy needs to access the actual underlying service. To do that safely, I do this over HTTPS and I created a service account and used the passport-http module to do BASIC authentication with the backend service.

Here’s a smallish node.js module that I wrote to accomplish this:

    var restify = require('restify'),
        userId = process.env.ID,
        pwd = process.env.PWD,
        passport = require('passport'),
        BasicStrategy = require('passport-http').BasicStrategy;

    passport.use(new BasicStrategy(
        function (username, password, done) {
            findByUsername(username, function (err, user) {
                if (err) {
                    return done(err);
                }
                if (!user) {
                    return done(null, false, { message: 'Incorrect username.' });
                }
                if (user.password !== password) {
                    return done(null, false, { message: 'Incorrect password.' });
                }
                return done(null, user);
            });
        }
    ));

    // Just use a single user that can access this service set from deployment var
    var users = [
        { id: 1, username: userId, password: pwd}
    ];

    function findByUsername(username, fn) {
        for (var i = 0, len = users.length; i < len; i++) {
            var user = users[i];
            if (user.username === username) {
                return fn(null, user);
            }
        }
        return fn(null, null);
    }

    exports.authenticate = function (req, res, next, callback) {
        passport.authenticate('basic', function (err, user) {
            if (err) {
                return next(err);
            }
            if (!user) {
                var error = new restify.InvalidCredentialsError("Failed to authenticate.");
                res.send(error);
                return next();
            }

            callback(req, res, next);
        })(req, res, next);
    };

To use the module, all you have to do is “require” it and make a call to it passing in a callback function to the REST service that you’ll end up calling once authenticated. This is a simple example of that:

    var basicAuth = require(__dirname + '/../utils/authn.js');

    exports.viewPostsByUid = function (req, res, next) {
        basicAuth.authenticate(req, res, next, function() {
            validateParam(req.params.uid, next);
            var url = '/posts/' + encodeURIComponent(req.params.uid);

            processRequest(req, res, next, url);
        });
    };

As you can see, it’s fairly trivial to protect your services with BASIC authentication and is a good line of defense for any attacks directly to the service itself.

Advertisements