Laravel Reverb: Private &amp; Presence Channel Auth at Scale | Mohamed Said        [  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png)   Mohamed Said Laravel Backend Engineer  ](https://msaied.com) [ Home ](https://msaied.com) [ Projects ](https://msaied.com/projects) [ Articles  ](https://msaied.com/articles) [ Certificates ](https://msaied.com/certificates) [ Contact ](https://msaied.com#contact-section) 

       [  ](https://github.com/EG-Mohamed)       

 [ Home ](https://msaied.com) [ Projects ](https://msaied.com/projects) [ Articles ](https://msaied.com/articles) [ Certificates ](https://msaied.com/certificates) [ Contact ](https://msaied.com#contact-section) 

  [ home ](https://msaied.com)    [ articles ](https://msaied.com/articles)    Laravel Broadcasting with Reverb: Per-Channel Authorization and Presence Channels at Scale        On this page       1. [  Why Channel Authorization Deserves More Attention ](#why-channel-authorization-deserves-more-attention)
2. [  Structuring Channel Routes for Real Authorization ](#structuring-channel-routes-for-real-authorization)
3. [  Presence Channels: The join Return Value Matters ](#presence-channels-the-codejoincode-return-value-matters)
4. [  Scaling Presence Sets ](#scaling-presence-sets)
5. [  Broadcasting Events Only to Authorized Channels ](#broadcasting-events-only-to-authorized-channels)
6. [  Key Takeaways ](#key-takeaways)

  ![Laravel Broadcasting with Reverb: Per-Channel Authorization and Presence Channels at Scale](https://cdn.msaied.com/208/b654521431b6021da07c8209170ed9e9.png)

  #laravel   #reverb   #broadcasting   #websockets   #real-time  

 Laravel Broadcasting with Reverb: Per-Channel Authorization and Presence Channels at Scale 
============================================================================================

     16 Jun 2026      3 min read    ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said  

       Table of contents

1. [  01   Why Channel Authorization Deserves More Attention  ](#why-channel-authorization-deserves-more-attention)
2. [  02   Structuring Channel Routes for Real Authorization  ](#structuring-channel-routes-for-real-authorization)
3. [  03   Presence Channels: The join Return Value Matters  ](#presence-channels-the-codejoincode-return-value-matters)
4. [  04   Scaling Presence Sets  ](#scaling-presence-sets)
5. [  05   Broadcasting Events Only to Authorized Channels  ](#broadcasting-events-only-to-authorized-channels)
6. [  06   Key Takeaways  ](#key-takeaways)

 Why Channel Authorization Deserves More Attention
-------------------------------------------------

Most tutorials stop at `Auth::check()` inside a channel route. In production, that is rarely enough. A multi-tenant SaaS, a collaborative document editor, or a live support dashboard each needs per-resource authorization that mirrors the same rules enforced in your HTTP layer — not a weaker copy of them.

Laravel Reverb is a first-party WebSocket server, but the authorization model is still driven by `routes/channels.php` and the `BroadcastServiceProvider`. Getting that layer right is the real work.

Structuring Channel Routes for Real Authorization
-------------------------------------------------

Avoid anonymous closures for anything non-trivial. Register a dedicated channel class instead:

```bash
php artisan make:channel OrderChannel

```

```php
// routes/channels.php
Broadcast::channel('orders.{orderId}', OrderChannel::class);

```

```php
// app/Broadcasting/OrderChannel.php
final class OrderChannel
{
    public function join(User $user, int $orderId): bool|array
    {
        $order = Order::findOrFail($orderId);

        // Reuse the same policy you use in controllers.
        return $user->can('view', $order);
    }
}

```

Using `$user->can()` delegates to your existing `OrderPolicy::view()` method. One rule, two enforcement points — no drift.

Presence Channels: The `join` Return Value Matters
--------------------------------------------------

For presence channels, returning `true` is not enough. You must return an array; that array becomes the member metadata broadcast to all subscribers.

```php
public function join(User $user, string $roomId): bool|array
{
    $room = ChatRoom::findOrFail($roomId);

    if (! $user->can('join', $room)) {
        return false;
    }

    return [
        'id'     => $user->id,
        'name'   => $user->display_name,
        'avatar' => $user->avatar_url,
    ];
}

```

Keep this payload small. Every subscriber receives it on `pusher:member_added`. Sending eager-loaded relationships here is a common mistake that bloats payloads and slows join acknowledgement.

Scaling Presence Sets
---------------------

Reverb stores presence membership in Redis by default when you configure the `reverb` driver with a Redis connection. The key concern at scale is **join/leave storms** — a deploy or network blip causes hundreds of clients to reconnect simultaneously.

Mitigate this with exponential back-off on the client side (Laravel Echo supports this via the `authEndpoint` retry config) and by keeping your auth endpoint fast:

```php
// config/broadcasting.php — tune the Reverb connection pool
'reverb' => [
    'driver' => 'reverb',
    'key'    => env('REVERB_APP_KEY'),
    'secret' => env('REVERB_APP_SECRET'),
    'app_id' => env('REVERB_APP_ID'),
    'options' => [
        'host'   => env('REVERB_HOST', '0.0.0.0'),
        'port'   => env('REVERB_PORT', 8080),
        'scheme' => env('REVERB_SCHEME', 'http'),
    ],
],

```

Cache the authorization result for short-lived presence joins (5–10 seconds is safe) using a tagged cache keyed on `user:{id}:channel:{name}`:

```php
public function join(User $user, string $roomId): bool|array
{
    return Cache::tags(['channel-auth'])
        ->remember("user:{$user->id}:room:{$roomId}", 8, function () use ($user, $roomId) {
            $room = ChatRoom::findOrFail($roomId);
            if (! $user->can('join', $room)) {
                return false;
            }
            return ['id' => $user->id, 'name' => $user->display_name];
        });
}

```

Invalidate the tag when room membership rules change (e.g., a user is removed from a room).

Broadcasting Events Only to Authorized Channels
-----------------------------------------------

Use `broadcastOn` to return a typed channel, not a raw string:

```php
final class OrderStatusUpdated implements ShouldBroadcast
{
    public function __construct(private readonly Order $order) {}

    public function broadcastOn(): array
    {
        return [new PrivateChannel("orders.{$this->order->id}")];
    }

    public function broadcastWith(): array
    {
        return ['status' => $this->order->status->value];
    }
}

```

Using `PrivateChannel` (or `PresenceChannel`) ensures Reverb enforces the auth handshake before delivering the event.

Key Takeaways
-------------

- **Delegate to policies**: reuse `Gate`/`Policy` inside channel classes — never duplicate authorization logic.
- **Return arrays from presence `join`**: returning `true` silently breaks presence membership metadata.
- **Keep join payloads minimal**: large arrays on `pusher:member_added` degrade performance for all subscribers.
- **Cache short-lived auth results**: reduces DB pressure during reconnect storms without meaningful security trade-offs.
- **Use typed channel classes**: `PrivateChannel` and `PresenceChannel` make intent explicit and prevent accidental public exposure.

 Found this useful?

          [  ](https://twitter.com/intent/tweet?url=https%3A%2F%2Fmsaied.com%2Farticles%2Flaravel-broadcasting-with-reverb-per-channel-authorization-and-presence-channels-at-scale&text=Laravel+Broadcasting+with+Reverb%3A+Per-Channel+Authorization+and+Presence+Channels+at+Scale) [  ](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fmsaied.com%2Farticles%2Flaravel-broadcasting-with-reverb-per-channel-authorization-and-presence-channels-at-scale) 

 Frequently Asked Questions 
----------------------------

  3 questions  

     Q01  Can I reuse Laravel policies inside channel authorization classes?        Yes. Call `$user-&gt;can('action', $model)` inside your channel's `join` method. It delegates to the same Gate and Policy you use in controllers, keeping authorization logic in one place. 

      Q02  What happens if a presence channel's `join` method returns `true` instead of an array?        Returning `true` grants access but sends no member metadata. Other subscribers won't receive meaningful data in `pusher:member_added` events, breaking any UI that displays who is online. 

      Q03  How do I handle reconnect storms in Reverb with many presence channel subscribers?        Cache the authorization result for a few seconds per user/channel pair using a tagged cache. This reduces database load during mass reconnects without weakening security, since the window is too short to be exploitable in practice. 

  Continue reading

 More Articles 
---------------

 [ View all    ](https://msaied.com/articles) 

 [ ![Pest 5 Released: Test Impact Analysis, Agent Verification, and Evals](https://cdn.msaied.com/493/a1d6434093b945e8a3291eb09c09e768.png) Pest PHP Testing PHP 8.4 

### Pest 5 Released: Test Impact Analysis, Agent Verification, and Evals

Pest v5 lands with the TIA engine that cut Laravel Cloud's 19,000-test suite from 3 minutes to 5 seconds, plus...

  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said 

 31 Jul 2026     4 min read  

  Read    

 ](https://msaied.com/articles/pest-5-released-test-impact-analysis-agent-verification-and-evals) [ ![Job Batching, Chaining, and Rate-Limited Middleware in Laravel Queues](https://cdn.msaied.com/489/89d47dc6b618d5435f9d7f333b75e922.png) laravel queues jobs 

### Job Batching, Chaining, and Rate-Limited Middleware in Laravel Queues

Go beyond basic dispatch: learn how to compose Laravel job batches with callbacks, chain dependent jobs safely...

  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said 

 30 Jul 2026     4 min read  

  Read    

 ](https://msaied.com/articles/job-batching-chaining-and-rate-limited-middleware-in-laravel-queues-3) [ ![Laravel Observers vs. Model Events: Choosing the Right Hook for Domain Side-Effects](https://cdn.msaied.com/488/451564d0a43aa33809619fa299027222.png) laravel eloquent domain-events 

### Laravel Observers vs. Model Events: Choosing the Right Hook for Domain Side-Effects

Model events and observers look similar but behave differently under bulk operations, transactions, and test i...

  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said 

 30 Jul 2026     4 min read  

  Read    

 ](https://msaied.com/articles/laravel-observers-vs-model-events-choosing-the-right-hook-for-domain-side-effects) 

   [  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png)   Mohamed Said Laravel Backend Engineer  ](https://msaied.com)Senior Backend Engineer specializing in Laravel, scalable SaaS platforms, APIs, and cloud infrastructure. I build secure, high-performance web applications that help businesses grow.

Explore

- [Home](https://msaied.com)
- [Projects](https://msaied.com/projects)
- [Articles](https://msaied.com/articles)
- [Certificates](https://msaied.com/certificates)
- [Contact](https://msaied.com#contact-section)

Connect

- [   hello@msaied.com ](mailto:hello@msaied.com)
- [   +20 109 461 9204 ](tel:+201094619204)

© 2026 Mohamed Said. All rights reserved.

 [  ](https://github.com/EG-Mohamed) [  ](https://www.linkedin.com/in/msaiedm/) [  ](https://wa.me/201094619204) [  ](mailto:hello@msaied.com) [  ](https://drive.google.com/file/u/0/d/1MF20IPRJyzfy32mhEutjL5EpSls0w2Q8/view)
