Turning Faye into a push-only server

This came up on the mailing list recently, and I had the same problem writing Primer’s real-time component. I want to turn my Faye server into a push-only server, meaning that only the server is allowed to publish messages and all other clients can only listen. This of course means we need some authentication.

The simplest way to do this is to have a password which is known only to your server-side application, and not exposed to the outside world. Your Faye server should then validate that any published messages contain the password before it allows them to be published. Let’s implement this as an extension:

var ServerAuth = {
  incoming: function(message, callback) {
    if (/^\/meta\//.test(message.channel))
      return callback(message);
    
    var password = message.ext && message.ext.password;
    
    if (password !== APP_PASSWORD)
      message.error = Faye.Error.extMismatch();
    
    if (password) delete message.ext.password;
    callback(message);
  }
};

This extension filters incoming messages on the server side. We let meta-messages through so that all clients can still connect and subscribe to channels. If a message is not in the /meta/* namespace, it is a publish message and must be authorized. We add an error if the password is invalid, since adding an error will stop the server from distributing it. Finally we delete the password from the message: if it is left in place, it will be broadcast when the message goes back out to clients, and will be visible to anyone with a working Firebug console.

To satisfy this authorization extension, we need a client extension that adds the password to all outgoing messages:

var ClientAuth = {
  outgoing: function(message, callback) {
    message.ext = message.ext || {};
    message.ext.password = APP_PASSWORD;
    callback(message);
  }
};

Finally we just need to add these extensions to our server-side components and set a password:

APP_PASSWORD = 'something super secret';
server.addExtension(ServerAuth);
server.getClient().addExtension(ClientAuth);

And voila, only your server can publish messages.

This is a very useful pattern when you need to make sure that data being sent to your client-side apps came from your server. For example, in Primer I use Faye to publish updates to the current page’s HTML, and I don’t want anybody to be able to inject arbitrary HTML into my site. If I know the HTML came from my server, I know it’s safe to inject it into the page.