Authentication

Public channels are open to anyone with your app key. For private and presence channels your own server decides who may subscribe, using a signature that only it can produce.

The flow

  1. A client subscribes to private-room-1.
  2. The client library sends socket_id and channel_name to your authorization endpoint (a normal HTTP POST, with your session cookie).
  3. Your server checks that this user may join that channel. If so, it answers with a signed token made with your app secret.
  4. The client hands that token to Vixus Push, which verifies the signature and lets the subscription through.

The secret never leaves your server, and a client without a valid token cannot join.

On the client

Tell pusher-js where your endpoint is:

js

const pusher = new Pusher("YOUR_APP_KEY", {
  cluster: "",
  wsHost: "YOUR_HOST",
  wsPort: 443,
  wssPort: 443,
  forceTLS: true,
  enabledTransports: ["ws", "wss"],
  channelAuthorization: {
    endpoint: "/api/pusher/auth",
    transport: "ajax",
  },
});

const channel = pusher.subscribe("private-room-1");

The library POSTs socket_id and channel_name as form fields and sends cookies for same-site endpoints. Your host and port are on your app's Overview page, see Quickstart.

On the server

This is a complete Next.js route handler. The pattern is the same in any framework: check the user, then return what authorizeChannel gives you.

ts

import Pusher from "pusher";

const pusher = new Pusher({
  appId: process.env.PUSHER_APP_ID!,
  key: process.env.PUSHER_APP_KEY!,
  secret: process.env.PUSHER_APP_SECRET!,
  host: process.env.PUSHER_HOST!,
  port: process.env.PUSHER_PORT!,
  useTLS: true,
});

export async function POST(request: Request) {
  const user = await getCurrentUser(request); // your own session check
  if (!user) return new Response("Unauthorized", { status: 401 });

  const form = await request.formData();
  const socketId = String(form.get("socket_id"));
  const channel = String(form.get("channel_name"));

  // Your rule: may this user join this channel?
  if (!(await canJoin(user, channel))) {
    return new Response("Forbidden", { status: 403 });
  }

  return Response.json(pusher.authorizeChannel(socketId, channel));
}

Presence channels

For presence channels pass the member's identity as a third argument. user_id is required and identifies the member; user_info is shown to everyone else on the channel, so only put in what they may see.

ts

return Response.json(
  pusher.authorizeChannel(socketId, channel, {
    user_id: String(user.id),
    user_info: { name: user.name },
  }),
);

Laravel

Laravel does this for you. Register the broadcasting routes, define who may join in routes/channels.php, and Laravel Echo sends the requests, see the Laravel tab in the Quickstart.

User authentication

An app can also let a client sign in as a user (separate from joining channels). Switch on User authentication in your app's Settings, point the client at an endpoint with userAuthentication: { endpoint }, and answer it with pusher.authenticateUser(socketId, { id: "42" }). It applies to connections opened after you enable it. We run the underlying server's implementation but do not test it ourselves.