Authenticating users

Pusher Channels will only allow a connection to subscribe to a private channel or presence channel if the connection provides an auth token signed by your server. This lets you restrict access. For example, if only your user Bob should be able to see the events in the channel private-user-bob, your server should only give Bob an auth token for this channel. Your server can also add user data to the auth token, which is used by presence channels to tell all subscribers who else is subscribed. When your client subscribes to a private or presence channel, the Channels client library requests an auth token from your server:

Auth Process

Server-side: implementing authentication endpoints

You can start with an authentication endpoint that authorizes every request it receives. You can do that with pusher-channels-auth-example, or by copy-pasting one of the examples below. (If you don't see your language listed, you can implement your own authentication endpoint or get in touch.)

Implementing the auth endpoint for a private channel

  • Rails
  • Drupal
  • Laravel
  • Wordpress
  • Node.js
  • objc
  • Python (Flask)
  • Go
  • Pusher CLI
1
2
3
4
5
6
7
8
9
10
  class PusherController < ApplicationController
  def auth
    if current_user
      response = pusher_client.authenticate(params[:channel_name], params[:socket_id])
      render json: response
    else
      render text: 'Forbidden', status: '403'
    end
  end
end

Implementing the auth endpoint for a presence channel

  • Rails
  • Drupal
  • Laravel
  • Wordpress
  • Node.js
  • objc
  • Python (Flask)
  • Go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class PusherController < ApplicationController

  def auth
    if current_user
      response = pusher_client.authenticate(params[:channel_name], 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: 'Forbidden', status: '403'
    end
  end
end

General notes

In all cases, the format of the response is very similar:

  • Unsuccessful responses from an authentication endpoint should serve a 403 Forbidden HTTP status.
  • Successful responses from an authentication endpoint should carry a 200 OK HTTP status and a body of the form { "auth": "$AUTHORIZATION_STRING" }. Authentication of a presence channel is performed in exactly the same way as a private channel but the JSON response must also have a channel_data property containing information that you wish to share about the current user. For more details of this format, see generating the authentication string.

Client-side: setting the Channel Authentication endpoint

The destination of the authentication request can be configured.

  • JavaScript
  • iOS
  • Java
  • Laravel Echo
1
new Pusher('app_key', { authEndpoint: '/pusher_auth.php' });

The default value for this is: /pusher/auth

CSRF-protected authentication endpoints

If the authentication endpoint is protected by a CSRF filter, then you can pass in a CSRF token via the auth hash under headers.

1
2
3
4
5
6
7
8
var pusher = new Pusher('app_key', {
  authEndpoint: '/pusher_auth.php',
  auth: {
    headers: {
      'X-CSRF-Token': "SOME_CSRF_TOKEN"
    }
  }
});

Note that you should change the name of the CSRF token key to the convention you prefer.

As an example, in Rails, you can inject the CSRF token into Javacript like this using ERB

1
2
3
4
5
6
7
8
9
10
<script>
  var pusher = new Pusher('app_key', {
    authEndpoint: '/pusher/auth',
    auth: {
      headers: {
        'X-CSRF-Token': "<%%= form_authenticity_token %>"
      }
    }
  });
</script>

Batching auth requests (aka multi-auth)

Currently, pusher-js itself does not support authenticating multiple channels in one HTTP request. However, thanks to Dirk Bonhomme you can use the pusher-js-auth plugin that buffers subscription requests and sends auth requests to your endpoint in batches.

Using JSONP in pusher-js

In the browser, if your authentication endpoint is on a different domain to the web application, you need to work around the browser's same-origin policy. For modern browsers, you should use Cross-Origin Resource Sharing (CORS); however, for older clients, pusher-js also supports JSONP. To enable this, set authTransport: 'jsonp':

1
2
3
4
5
6
7
<script src="//js.pusher.com/5.0/pusher.min.js"></script>
<script>
  var pusher = new Pusher('MY_PUSHER_KEY', {
    authTransport: 'jsonp',
    authEndpoint: 'http://myserver.com/pusher_jsonp_auth'
  });
</script>

With this set, the auth request parameters are passed in the query string, and an additional parameter called callback will be passed to the authentication endpoint. The authentication response must then be JavaScript that calls the named callback function with the authentication response. Here are some examples of generating this response for private channels:

  • Rails
  • Node.js
  • PHP/Drupal
  • PHP/Wordpress
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class PusherController < ApplicationController

  def auth
    if current_user
      auth = pusher_client.authenticate(params[:channel_name], params[:socket_id])

      render(
        text: params[:callback] + "(" + auth.to_json + ")",
        content_type: 'application/javascript'
      )
    else
      render text: 'Forbidden', status: '403'
    end
  end
end