Adding private channels to Pusher

Adding-private-channels-to-pusher.png

Pusher's private channels allow you to ensure that, for specific channels, the user connections to the these channels are authorized. This has been a highly requested feature, and we're really pleased to be releasing it today.

Introduction

Adding private channels to Pusher

Pusher‘s private channels allow you to ensure that, for specific channels, the user connections to the these channels are authorized. This has been a highly requested feature, and we’re really pleased to be releasing it today.

Note that private channels are not required for all applications. For example, on a shopping site, you might want to broadcast changes in stock for a product to your visitors – authenticating this information would probably only add overhead for this application.

I’d like to spend some time explaining the current state of security in Pusher, and our implementation of private channels. I think it’s pretty interesting, but if you’re just interested in getting started straight away please skip to the last section!

The obvious benefit of private channels is that it allows a fully authenticated route from your application, via Pusher, to the browser. Adding end-to-end encryption would be the next step, via an SSL API and SSL WebSocket connection. This is something we’re considering, so please get in touch if this would be of interest to you.

The other advantage of authenticating channels, which informed our design, is that it enables us to trust communication from the browser to the socket on a given channel. But that’s for another day!

How we implemented private channels

Private channels are an optional feature. To avoid adding the complexity of another API call we simply have a naming convention for private channels. If a channel name begins with private-, it is private, and you must supply an authorization string when you subscribe to that channel.

The authorization scheme is based on the idea that, rather than implementing custom user authentication, and adding complexity and state to pusher, we should trust the existing level of authentication offered by your application. We also wanted to ensure that someone reading data sent from your application to the browser would not be able to connect to a channel as that user, and therefore couldn’t include any secrets in the page HTML.

As shown in this diagram, a unique socket id is generated and sent to the browser by Pusher. This is sent to your application (1) via an AJAX request which authorizes the user to access the channel against your existing authentication system. If successful your application returns an authorization string to the browser signed with you Pusher secret. This is sent to Pusher over the WebSocket, which completes the authorization (2) if the authorization string matches.

Getting started example with Ruby

Suppose you have a channel called project-3, to which users A and B have access, but not C. You’d like to make this channel private so that user C cannot listen in on the private events. Simply send events to private-project-3 and subscribe to it in the browser. As long as you’re using the latest javascript (version 1.3 or above), you’ll see that a POST request is made to your application to /pusher/auth. This will currently fail, and therefore the subscribe request will not be made to the socket.

To implement this in Sinatra you might do something like this.

1post "/pusher/auth" do
2user = authenticate_user()
3
4project = Project.for_channel(params[:channel_name])
5
6if user && project.users.include?(user)
7auth = Pusher[params[:channel_name]].socket_auth(params[:socket_id])
8
9content_type "application/json"
10return JSON.generate({
11:auth => auth
12})
13else
14halt 403, "Not authorized"
15end
16end

For more information, and for details on the authorization string, see private channel docs. And if you haven’t done so already, feel free to create a free Pusher account and let us know what you think!