AuthorizationPresence channels

Presence channel authorization

Presence channels add a channel_data payload that becomes the public profile every other subscriber sees. Your auth endpoint includes it alongside the signature.

Shape

{
  "auth": "YOUR_KEY:hex_hmac_sha256",
  "channel_data": "{\"user_id\":\"42\",\"user_info\":{\"name\":\"Alice\"}}"
}

channel_data is a JSON-encoded string (yes, a string, even though it contains JSON — Pusher’s protocol).

The user_id must be unique per user; user_info is whatever public data you want subscribers to see (name, avatar URL, etc.). Don’t put secrets in here — it’s broadcast to every other member.


Laravel

routes/channels.php:

Broadcast::channel('room.{id}', function ($user, $id) {
    return [
        'id'     => $user->id,        // becomes user_id
        'name'   => $user->name,
        'avatar' => $user->avatar_url,
    ];
});

Returning an array signals “this is a presence channel.” Returning true would have made it private.


Node.js

const presence = {
  user_id: String(req.session.userId),
  user_info: {
    name: req.session.name,
    avatar: req.session.avatar,
  },
};
 
const auth = pusher.authorizeChannel(socket_id, channel_name, presence);
res.json(auth);

PHP

$auth = $pusher->authorizePresenceChannel(
    $_POST['channel_name'],
    $_POST['socket_id'],
    (string) $userId,
    [
        'name'   => $user->name,
        'avatar' => $user->avatar_url,
    ],
);
header('Content-Type: application/json');
echo $auth;

Python

auth = p.authenticate(
    channel=channel,
    socket_id=socket_id,
    custom_data={
        'user_id': str(user_id),
        'user_info': {
            'name': user.name,
            'avatar': user.avatar_url,
        },
    },
)
return jsonify(auth)

Tips

  • The total channel_data payload is capped at 10 KB. Keep user_info small.
  • The same user_id can have multiple connected sockets (open in many tabs). Mawjly counts them as one member with multiple subscriptions — user_count and subscription_count differ.
  • member_added only fires when a brand-new user_id joins; second tab from the same user is silent.