Docs

  • Channels Channels
  • Beams Beams
  • Developers
  • Support
  • Blog
  • Sign up
    • Search powered by Algolia
    • Sign in
    • Sign up
    • Channels
    • Getting started
      • SDK quick starts
        • JavaScript quick start
        • iOS quick start
        • Android quick start
        • Flutter quick start
        • React Native quick start
      • Use case quick starts
        • Javascript realtime chart
        • Javascript realtime user list
      • Debugging
    • Using channels
      • Client API overview
      • Connection
      • User authentication
      • Watchlist events
      • Functions
      • Authorized connections
      • Channels
      • Public channels
      • Private channels
      • Encrypted channels
      • Presence channels
      • Cache channels
      • Events
      • Global configuration
      • Websocket fallbacks
      • Device compatibility
    • Server api
      • Overview
      • HTTP API interaction
      • Webhooks
      • Authenticating users
      • Authorizing users
      • Sending events to authenticated users
      • Terminating user connections
      • Excluding event recipients
    • Channels libraries
      • API libraries
    • Pusher cli
      • Overview
      • Installation
      • Documentation
    • Miscellaneous
      • Clusters
      • Integrations
      • Resources
    • Library auth reference
      • Authentication and authorization signatures
      • HTTP API reference
      • Pusher Channels Protocol
      • Server library reference specification
      • Logging
    • Beams
    • Pusher lab

    Authorizing users

    Pusher provides mechanisms for both authenticating and authorizing users. Our definition of this is that the former identifies who a user is, while the latter controls access by a given user to certain resources.

    Since your servers are the authority on who your users are, and what they can access, our clients libraries are able to make callbacks to endpoints of your choice to supply signed authentication and authorization tokens for the bearing user.

    This page discusses implementing a user authorization endpoint using the Pusher Channels server libraries. If you’re looking for information on implementing a user authentication endpoint, check the Authenticating users page.

    Pusher Channels originally supported pure authorization in private channels. With these authorization tokens it was not evident who the bearer was, but their token allowed them access to certain private channels. In presence channels, we added user info to the authorization token to provide extra information about who was connected (so that it could be distributed to other members of a channel). These tokens function as authentication and authorization within the scope of the presence channel.

    We now support User authentication to extend this scheme and to add more functionality. We’ve made this backwards compatible with the old presence channel authorization mechanism, but we do encourage users to adopt the newer styles that will be used in future to add additional features.

    One of the results of using User Authentication is that providing the user object in presence channel authorization is optional, if the user is already signed-in using User Authentication.

    Note that in libraries that haven’t been updated yet, the authorization function is still called authenticate.

    ∞ Channel subscription authorization

    Pusher Channels will only allow a connection to subscribe to a private channel or presence channel if the connection provides an authorization 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 authorization token from your server:

    Authorization Process

    You can start with an authorization 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 authorization endpoint or get in touch.)

    ∞ Implementing the authorization endpoint for a private channel

    class PusherController < ApplicationController
    def auth
    if current_user
    # This authenticates every user. Don't do this in production!
    response = Pusher.authenticate(params[:channel_name], params[:socket_id])
    render json: response
    else
    render text: 'Forbidden', status: '403'
    end
    end
    end
    global $user;
    if ($user->uid) {
    echo $pusher->authorizeChannel($_POST['channel_name'], $_POST['socket_id']);
    } else {
    header('', true, 403);
    echo "Forbidden";
    }
    // More information: https://laravel.com/docs/master/broadcasting#authorizing-channels

    // The user will have already been authenticated by Laravel. In the
    // below callback, we can check whether the user is _authorized_ to
    // subscribe to the channel.

    // In routes/channels.php
    Broadcast::channel('user.{userId}', function ($user, $userId) {
    return $user->id === $userId;
    });
    if ( is_user_logged_in() ) {
    // Make sure you check user is authorized in your `is_user_logged_in` check.
    echo $pusher->authorizeChannel($_POST['channel_name'], $_POST['socket_id']);
    } else {
    header('', true, 403);
    echo "Forbidden";
    }
    // First install the dependencies:
    // npm install pusher express cors

    const express = require("express");
    const cors = require("cors");
    const Pusher = require("pusher");
    const pusher = new Pusher({
    appId: "APP_ID",
    key: "APP_KEY",
    secret: "APP_SECRET",
    cluster: "APP_CLUSTER",
    useTLS: true,
    });
    const app = express();

    app.use(express.json());
    app.use(express.urlencoded({ extended: false }));
    app.use(cors());
    app.post("/pusher/auth", (req, res) => {
    const socketId = req.body.socket_id;
    const channel = req.body.channel_name;
    // This authenticates every user. Don't do this in production!
    const authResponse = pusher.authorizeChannel(socketId, channel);
    res.send(authResponse);
    });

    const port = process.env.PORT || 5000;
    app.listen(port);
    using PusherServer;
    public class MyController : Controller {
    public ActionResult Auth(string channel_name, string socket_id) {
    // This authenticates every user. Don't do this in production!
    var auth = pusher.Authenticate( channel_name, socketId );
    var json = auth.ToJson();
    return new ContentResult { Content = json, ContentType = "application/json" };
    }
    }
    @app.route("/pusher/auth", methods=['POST'])
    def pusher_authentication():

    # This authenticates every user. Don't do this in production!
    # pusher_client is obtained through pusher.Pusher( ... )
    auth = pusher_client.authenticate(
    channel=request.form['channel_name'],
    socket_id=request.form['socket_id']
    )
    return json.dumps(auth)
    func pusherAuth(res http.ResponseWriter, req *http.Request) {
    params, _ := ioutil.ReadAll(req.Body)
    // This authenticates every user. Don't do this in production!
    response, err := pusherClient.AuthorizePrivateChannel(params)

    if err != nil {
    panic(err)
    }

    fmt.Fprintf(res, string(response))
    }

    func main() {
    http.HandleFunc("/pusher/auth", pusherAuth)
    http.ListenAndServe(":5000", nil)
    }
    #This will authorize _all_ users. Only use for debugging!
    pusher channels generate auth-server --app-id APP_ID

    ∞ Implementing the authorization endpoint for a presence channel

    class PusherController < ApplicationController
    def auth
    if current_user
    # This authenticates every user. Don't do this in production!
    response = Pusher.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
    global $user;
    if ($user->uid) {
    $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( "Forbidden" );
    }
    // More information: https://laravel.com/docs/master/broadcasting#authorizing-channels
    //
    // The user will have already been authenticated by Laravel. In the
    // below callback, we can check whether the user is _authorized_ to
    // subscribe to the channel.
    //
    // In routes/channels.php
    Broadcast::channel('user.{userId}', function ($user, $userId) {
    if ($user->id === $userId) {
    return array('name' => $user->name);
    }
    });
    if ( is_user_logged_in() ) {
    global $current_user;
    get_currentuserinfo();
    $presence_data = array('name' => $current_user->display_name);
    // Make sure you check user is authorized in your `is_user_logged_in` check.
    echo $pusher->presence_auth($_POST['channel_name'], $_POST['socket_id'], $current_user->ID, $presence_data);
    } else {
    header('', true, 403);
    echo( "Forbidden" );
    }
    // npm install pusher
    // npm install express
    // npm install cors

    const express = require("express");
    const cors = require("cors");
    const Pusher = require("pusher");
    const pusher = new Pusher({
    appId: "APP_ID",
    key: "APP_KEY",
    secret: "APP_SECRET",
    cluster: "APP_CLUSTER",
    useTLS: true,
    });
    const app = express();
    app.use(express.json());
    app.use(express.urlencoded({ extended: false }));
    app.use(cors());
    app.post("/pusher/auth", function (req, res) {
    const socketId = req.body.socket_id;
    const channel = req.body.channel_name;
    const presenceData = {
    user_id: "unique_user_id",
    user_info: { name: "Mr Channels", twitter_id: "@pusher" },
    };
    // This authenticates every user. Don't do this in production!
    const authResponse = pusher.authorizeChannel(socketId, channel, presenceData);
    res.send(authResponse);
    });
    const port = process.env.PORT || 5000;
    app.listen(port);
    using PusherServer;

    public class MyController : Controller {
    public ActionResult Auth(string channel_name, string socket_id) {
    var channelData = new PresenceChannelData() {
    user_id: "unique_user_id",
    user_info: new {
    name = "Mr Channels",
    twitter_id = "@pusher"
    }
    };
    // This authenticates every user. Don't do this in production!
    var auth = pusher.Authenticate( channelName, socketId, channelData );
    var json = auth.ToJson();
    return new ContentResult { Content = json, ContentType = "application/json" };
    }
    }
    @app.route("/pusher/auth", methods=['POST'])
    def pusher_authentication():

    # pusher_client is obtained through pusher_client = pusher.Pusher( ... )
    # This authenticates every user. Don't do this in production!
    auth = pusher_client.authenticate(
    channel=request.form['channel_name'],
    socket_id=request.form['socket_id'],
    custom_data={
    u'user_id': u'1',
    u'user_info': {
    u'twitter':
    u'@pusher'
    }
    }
    )
    return json.dumps(auth)
    params, _ := ioutil.ReadAll(req.Body)
    presenceData := pusher.MemberData{
    UserID: "1",
    UserInfo: map[string]string{
    "twitter": "pusher",
    },
    }
    // This authenticates every user. Don't do this in production!
    response, err := pusherClient.AuthorizePresenceChannel(params, presenceData)

    if err != nil {
    panic(err)
    }

    fmt.Fprintf(res, string(response))

    ∞ Response

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

    • Unsuccessful responses from an authorization endpoint should serve a 403 Forbidden HTTP status.
    • Successful responses from an authorization endpoint should carry a 200 OK HTTP status and a body of the form
      { "auth": "$AUTHORIZATION_STRING" }
      Authorization 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 authorization string.

    ∞ Client-side: setting the authorization endpoint

    The destination of the authentication and authorization requests can be configured.

    new Pusher("app_key", { channelAuthorization: { endpoint: "/pusher_auth.php"}  });
    self.pusher.authorizationURL = [NSURL URLWithString:@"http://www.yourserver.com/authorize"];
    HttpAuthorizer authorizer = new HttpAuthorizer("http://example.com/some_auth_endpoint");
    PusherOptions options = new PusherOptions().setAuthorizer(authorizer);
    Pusher pusher = new Pusher(YOUR_APP_KEY, options);
    window.Echo = new Echo({
    broadcaster: "pusher",
    key: "APP_KEY",
    forceTLS: true,
    authEndpoint: "/broadcasting/auth",
    });

    The default value for this is /pusher/auth.

    In order to connect to a private or presence channel using libPusher, you first need to configure your server authorization URL.

    When you attempt to connect to a private or presence channel, libPusher will make a form-encoded POST request to the above URL, passing along the socket_id and channel_name as parameters. Prior to sending the request, the PTPusherDelegate will be notified. The delegate function is passed an operation parameter, which allows you to access the NSMutableURLRequest instance that will be sent.

    It is up to you to configure the request to handle whatever authentication mechanism you are using. In this example, we set a custom header with a token which the server will use to authenticate the user before proceeding with authorization.

    - (void)pusher:(PTPusher *)pusher willAuthorizeChannel:(PTPusherChannel *)channel withAuthOperation:(PTPusherChannelAuthorizationOperation *)operation {
    [operation.mutableURLRequest setValue:@"some-authentication-token" forHTTPHeaderField:@"X-MyCustom-AuthTokenHeader"];
    }

    ∞ CSRF-protected authorization endpoint

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

    var pusher = new Pusher("app_key", {
    channelAuthorization: {
    endpoint: "/pusher_auth.php",
    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 Javascript like this using ERB

    <script>
    var pusher = new Pusher("app_key", {
    channelAuthorization: {
    endpoint: "/pusher/auth",
    headers: { "X-CSRF-Token": "<%= form_authenticity_token %>" },
    },
    });
    </script>

    ∞ Batching authorization requests (aka multi-auth)

    Currently, pusher-js itself does not support authorizing 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 authorization requests to your endpoint in batches.

    ∞ Using JSONP in pusher-js

    In the browser, if your authorization 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 channelAuthorization.transport: 'jsonp':

    <script src="//js.pusher.com/8.3.0/pusher.min.js"></script>
    <script>
    var pusher = new Pusher("MY_PUSHER_KEY", {
    channelAuthorization: {
    transport: "jsonp",
    endpoint: "http://myserver.com/pusher_jsonp_auth",
    },
    });
    </script>

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

    class PusherController < ApplicationController

    def auth
    if current_user
    auth = Pusher.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
    en

    end
    // Express.js setup
    // http://expressjs.com/

    ...

    app.get("/pusher/auth", (req, res) => {
    const query = req.query;
    const socketId = query.socket_id;
    const channel = query.channel_name;
    const callback = query.callback;

    const presenceData = {
    user_id: "some_id",
    user_info: {
    name: "John Smith"
    }
    };

    const auth = JSON.stringify(
    pusher.authorizeChannel(socketId, channel, presenceData)
    );
    const cb = callback.replace(/\\"/g,"") + "(" + auth + ");";

    res.set({
    "Content-Type": "application/javascript"
    });

    res.send(cb);
    });
    global $user;
    if ($user->uid)
    {
    $pusher = new Pusher(APP_KEY, APP_SECRET, APP_ID);
    $auth = $pusher->authorizeChannel($_GET['channel_name'], $_GET['socket_id']);

    $callback = str_replace('\\', '', $_GET['callback']);
    header('Content-Type: application/javascript');
    echo($callback . '(' . $auth . ');');
    }
    else
    {
    header('', true, 403);
    echo "Forbidden";
    }
    if ( is_user_logged_in() )
    {
    $pusher = new Pusher(APP_KEY, APP_SECRET, APP_ID);
    $auth = $pusher->authorizeChannel($_GET['channel_name'], $_GET['socket_id']);

    $callback = str_replace('\\', '', $_GET['callback']);
    header('Content-Type: application/javascript');
    echo($callback . '(' . $auth . ');');
    }
    else
    {
    header('', true, 403);
    echo "Forbidden";
    }

    Contents

    • Channel subscription authorization
    • Response
    • Client-side: setting the authorization endpoint
      • CSRF-protected authorization endpoint
    • Batching authorization requests (aka multi-auth)
    • Using JSONP in pusher-js

    Spotted something that isn’t quite right? Create an issue on GitHub.

    Copyright © 2024 Pusher Ltd. All rights reserved.

    • Support,
    • Status
    • Follow Pusher on Twitter Twitter
    • Subscribe to Pusher’s channel on YouTube
    • Follow Pusher on LinkedIn
    • Follow Pusher on Github GitHub
    • Follow Pusher on Twitch Twitch
    • Follow Pusher on Discord Discord
    OSZAR »