Authenticating users

Application security is very important so Pusher provides a mechanism for authenticating a user's access to a channel at the point of subscription.

This can be used both to restrict access to content private channels, and in the case of presence channels notify subscribers of who else is also subscribed via presence events.

The basic mechanism for doing this is broadly the same for both scenarios. The following sequence diagram shows the signing process:

A unique socket_id is generated and sent to the browser by Pusher. When an attempt is made to subscribe to a private- or presence- channel the socket_id and channel_name is sent to your application (1) via an AJAX POST request which authorises the user to access the channel against your existing authentication system. If successful your application returns an authorisation string (see generating the authentication signature) to the browser signed with your Pusher secret. This is sent to Pusher over the WebSocket, which completes the authorisation (2) if the authorisation string matches.

For example, in both the subscribe calls below an authentication request will take place.

var pusher = new Pusher('APP_KEY'); var privateChannel = pusher.subscribe('private-channel'); var presenceChannel = pusher.subscribe('presence-channel');

The destination of the HTTP POST request can be configured by setting a static property on the Pusher object.

Pusher.channel_auth_endpoint = '/pusher_auth.php';

The default value for this is: /pusher/auth

The purpose of the callback is so that you can check that the current user of your application has permission to access the channel that they are trying to subscribe to. How the user is authenticated depends on the decisions you make and the system you are developing. If the user does have permission to subscribe to the supplied channel then an HTTP response must be returned indicating that.

The HTTP POST request that is made to the authentication endpoint when a subscription takes place contains the following request parameters:

  • socket_id
    • A unique identifier for the specific client connection to Pusher
  • channel_name
    • The name of the channel being subscribed to

As discussed, the duty of the server is to check the user has permission to subscribe to the supplied channel. If the user does have permission then an authentication HTTP response must be returned in a JSON format with an authentication signature. We have a number of server libraries that make doing this really simple.

Note: If you don't want to use one of the existing libraries, or there isn't one in the technology you want to use, please see authenticating signatures or get in touch.

The following sections show how this is achieved for the different types of channels.

Types of channel

  • Private channels - used to control access to a source of information
  • Presence channels - used to control access, but also allows info about the user to be distributed to other users.

Implementing the auth endpoint for a private channel

Here are a number of examples of how to perform private channel authentication:

# Using https://github.com/pusher/pusher-gem class PusherController < ApplicationController protect_from_forgery :except => :auth # stop rails CSRF protection for this action def auth if current_user response = Pusher[params[:channel_name]].authenticate(params[:socket_id]) render :json => response else render :text => "Not authorized", :status => '403' end end end // Using: https://github.com/squeeks/Pusher-PHP global $user; if ($user->uid) { $pusher = new Pusher(APP_KEY, APP_SECRET, APP_ID); echo $pusher->socket_auth($_POST['channel_name'], $_POST['socket_id']); } else { header('', true, 403); echo "Not authorized"; } // Using: https://github.com/squeeks/Pusher-PHP if ( is_user_logged_in() ) { $pusher = new Pusher(APP_KEY, APP_SECRET, APP_ID); echo $pusher->socket_auth($_POST['channel_name'], $_POST['socket_id']); } else { header('', true, 403); echo "Not authorized"; }

The generated JSON should look as follows:

{
  "auth":"278d425bdf160c739803:a99e78e7cd40dcd0d4ae06be0a5395b6cd3c085764229fd40b39ce92c39af33e"
}

Implementing the auth endpoint for a presence channel

Authentication of a presence channel is performed in exactly the same way as a private channel but the JSON response must have a channel_data property containing information that you wish to share about the current user.

Here are a number of examples of how to perform presence channel authentication and provide additional user information to the channel:

# Using https://github.com/pusher/pusher-gem class PusherController < ApplicationController protect_from_forgery :except => :auth # stop rails CSRF protection for this action def auth if current_user response = Pusher[params[:channel_name]].authenticate(params[:socket_id], { :user_id => current_user.id, # => required :user_info => { # => optional - for example :name => current_user.name, :email => current_user.email } }) render :json => response else render :text => "Not authorized", :status => '403' end end end // Using: https://github.com/squeeks/Pusher-PHP global $user; if ($user->uid) { $pusher = new Pusher(APP_KEY, APP_SECRET, APP_ID); $presence_data = array('name' => $user->name); echo $pusher->presence_auth($_POST['channel_name'], $_POST['socket_id'], $user->uid, $presence_data); } else { header('', true, 403); echo( "Not authorized" ); } // Using: https://github.com/squeeks/Pusher-PHP if ( is_user_logged_in() ) { global $current_user; get_currentuserinfo(); $pusher = new Pusher(APP_KEY, APP_SECRET, APP_ID); $presence_data = array('name' => $current_user->display_name); echo $pusher->presence_auth($_POST['channel_name'], $_POST['socket_id'], $current_user->ID, $presence_data); } else { header('', true, 403); echo( "Not authorized" ); }

The generated JSON should look similar to the private channel JSON with an additional channel_data property which should be valid JSON encoded as a string:

{
  "auth":"49e26cb8e9dde3dfc009:a8cf1d3deefbb1bdc6a9d1547640d49d94b4b512320e2597c257a740edd1788f",
  "channel_data":"{\"user_id\":\"Phil Leggetter\",\"user_info\":{\"name\":\"Phil Leggetter\",\"imageUrl\":\"http:\\\/\\\/www.gravatar.com\\\/avatar\\\/ecc56977271e781991b6172c16248459?s=80&d=mm&r=g\"}}"
}