whowho

Authenticating reverse-proxy for writing simpler apps

Usage no npm install needed!

<script type="module">
  import whowho from 'https://cdn.skypack.dev/whowho';
</script>

README

whowho

A simple authenticating proxy for your apps.

Installation

npm install --save whowho

Configuration

There are four items that need to be in place for your app to work correctly, all of which can be found in the configuration object passed to the constructor:

targets

This is a hash of paths and hosts/ports that you want to proxy to. For instance:

targets: {
  '/*': 'http://localhost:8000'
}

This will proxy to an app running on the same machine on port 8000. If your proxy is only proxying one page, make sure you haven't forgotten the asterisk on the path. Otherwise, it will literally only match the / path.

If you need to, you can also specify publicTargets which won't be authenticated, e.g. for assets. However, in production, I encourage you to use nginx or another static server for assets.

strategies

These are normal PassportJS strategies, tied to their name. The various strategies need to be required from their packages, such as var LocalStrategy = require('passport-local').Strategy;. You can then write the following:

strategies: {
  local: new LocalStrategy(
           function(username, password, done) {
             if(username === 'admin' && password === 'admin') {
               return done(null, {
                 id:1,
                 name:{
                   givenName:'Admin',
                 familyName:'Root'}
               });
             } else {
               return done(null, false, {
                 message: 'Wrong username or password.'
               });
             }
           })
}

This represents a simple authentication for username admin and password admin.

auth

This represents how you want to authentiate to WhoWho. For instance, to continue the above example:

auth: {
  'post /login': function(passport){
    return passport.authenticate('local', {
      successRedirect: '/', 
      failureRedirect: '/login'
    });
  }
}

serializeUser/deserializeUser

Okay, I'm cheating; these are two functions, not one. This is for your caching layer.

For this example, we'll cheat, and do it in memory. This is a Bad IdeaTM for a few reasons, but I don't want to muddle the example with Redis calls or similar.

Suppose that before creating the proxy, you had created a users hash:

var users = {};

Then, in your WhoWho config, you could simply use:

serializeUser: function(user, done){
  users[user.id] = user;
  done(null, user.id);
},
deserializeUser: function(id, done){
  done(null, users[id]);
}

Sample config

Putting the above all together in a full example, you'd get:

var passport = require('passport');
var AuthProxy = require('whowho').AuthProxy;
var LocalStrategy = require('passport-local').Strategy;

var users = {};

var proxyServer = new AuthProxy({
  strategies: {
    local: new LocalStrategy(
             function(username, password, done) {
               if(username === 'admin' && password === 'admin') {
                 return done(null, {
                   id:1,
                   name:{
                     givenName:'Admin',
                   familyName:'Root'}
                 });
               } else {
                 return done(null, false, {
                   message: 'Wrong username or password.'
                 });
               }
             })
  },
  auth: {
    'post /login': function(passport){
      return passport.authenticate('local', {
        successRedirect: '/', 
        failureRedirect: '/login'
      });
    }
  },
  targets: {
    '/*': 'http://localhost:8000'
  },
  serializeUser: function(user, done){
    users[user.id] = user;
    done(null, user.id);
  },
  deserializeUser: function(id, done){
    done(null, users[id]);
  }
});

proxyServer.start();

This simple script will run on the default port (3000) and proxy authenticated users through to the app running on port 8000. Unauthenticated users will see a "403 Forbidden" message.