Laravel Reverb: Private Channels &amp; Auth Guards | 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: Private Channels, Presence, and Auth Guards        On this page       1. [  Laravel Reverb: Private Channels, Presence, and Auth Guards ](#laravel-reverb-private-channels-presence-and-auth-guards)
2. [  Channel Authorization Fundamentals ](#channel-authorization-fundamentals)
3. [  Wiring a Non-Default Auth Guard ](#wiring-a-non-default-auth-guard)
4. [  Presence Channel Member Tracking ](#presence-channel-member-tracking)
5. [  Dispatching Events to Specific Channels ](#dispatching-events-to-specific-channels)
6. [  Testing Channel Authorization ](#testing-channel-authorization)
7. [  Key Takeaways ](#key-takeaways)

  ![Laravel Broadcasting with Reverb: Private Channels, Presence, and Auth Guards](https://cdn.msaied.com/416/26c2793902d9db428140205417b2dfb4.png)

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

 Laravel Broadcasting with Reverb: Private Channels, Presence, and Auth Guards 
===============================================================================

     12 Jul 2026      4 min read    ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said  

       Table of contents

1. [  01   Laravel Reverb: Private Channels, Presence, and Auth Guards  ](#laravel-reverb-private-channels-presence-and-auth-guards)
2. [  02   Channel Authorization Fundamentals  ](#channel-authorization-fundamentals)
3. [  03   Wiring a Non-Default Auth Guard  ](#wiring-a-non-default-auth-guard)
4. [  04   Presence Channel Member Tracking  ](#presence-channel-member-tracking)
5. [  05   Dispatching Events to Specific Channels  ](#dispatching-events-to-specific-channels)
6. [  06   Testing Channel Authorization  ](#testing-channel-authorization)
7. [  07   Key Takeaways  ](#key-takeaways)

 Laravel Reverb: Private Channels, Presence, and Auth Guards
-----------------------------------------------------------

Laravel Reverb ships as a first-party WebSocket server, and getting a public channel broadcasting is trivial. The interesting — and production-critical — work starts when you lock down private and presence channels and integrate them with non-default auth guards.

### Channel Authorization Fundamentals

Every private or presence channel subscription triggers a POST to `/broadcasting/auth`. Laravel resolves the channel class, calls its `join` (presence) or implicit boolean (private) method, and returns either a 200 or 403.

Register channel classes in `routes/channels.php` or a dedicated service provider:

```php
// routes/channels.php
use App\Broadcasting\OrderChannel;

Broadcast::channel('orders.{orderId}', OrderChannel::class);

```

```php
// app/Broadcasting/OrderChannel.php
namespace App\Broadcasting;

use App\Models\Order;
use App\Models\User;

class OrderChannel
{
    public function join(User $user, int $orderId): array|bool
    {
        $order = Order::findOrFail($orderId);

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

        // Returning an array makes this a presence channel payload.
        return [
            'id'   => $user->id,
            'name' => $user->name,
        ];
    }
}

```

Returning `false` or throwing an `AuthorizationException` sends a 403. Returning an array automatically upgrades the channel to presence semantics.

### Wiring a Non-Default Auth Guard

The broadcasting auth route uses the `web` guard by default. API-only apps authenticating via Sanctum tokens need an explicit override.

```php
// app/Providers/BroadcastServiceProvider.php
use Illuminate\Support\Facades\Broadcast;

public function boot(): void
{
    Broadcast::routes(['middleware' => ['auth:sanctum']]);

    require base_path('routes/channels.php');
}

```

On the JavaScript side, pass the auth headers when constructing the Echo instance:

```javascript
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';

window.Echo = new Echo({
    broadcaster: 'reverb',
    key: import.meta.env.VITE_REVERB_APP_KEY,
    wsHost: import.meta.env.VITE_REVERB_HOST,
    wsPort: import.meta.env.VITE_REVERB_PORT,
    forceTLS: false,
    auth: {
        headers: {
            Authorization: `Bearer ${yourSanctumToken}`,
        },
    },
});

```

Without the `Authorization` header the `/broadcasting/auth` endpoint returns 401 and the subscription silently fails — a common gotcha.

### Presence Channel Member Tracking

Presence channels expose `here`, `joining`, and `leaving` callbacks on the client:

```javascript
Echo.join(`orders.${orderId}`)
    .here(members  => console.log('Online now:', members))
    .joining(member => console.log('Joined:', member.name))
    .leaving(member => console.log('Left:', member.name))
    .listen('OrderStatusUpdated', e => updateUI(e.order));

```

Reverb tracks member state in memory per worker process. If you run multiple Reverb workers behind a load balancer, members connected to different workers won't see each other unless you configure a shared Redis presence driver. Set `REVERB_SCALING_ENABLED=true` and point `REVERB_REDIS_*` variables at your Redis instance.

### Dispatching Events to Specific Channels

```php
use App\Events\OrderStatusUpdated;

broadcast(new OrderStatusUpdated($order))->toOthers();

```

The `toOthers()` call suppresses the event for the socket that triggered it, preventing echo loops in collaborative UIs. It relies on the `X-Socket-ID` header being sent by Echo — verify your frontend sets it.

### Testing Channel Authorization

Pest makes channel auth assertions clean:

```php
use App\Models\{Order, User};
use Illuminate\Support\Facades\Broadcast;

it('authorizes the order owner to join the channel', function () {
    $user  = User::factory()->create();
    $order = Order::factory()->for($user)->create();

    $this->actingAs($user);

    $response = $this->postJson('/broadcasting/auth', [
        'channel_name' => "private-orders.{$order->id}",
        'socket_id'    => '123.456',
    ]);

    $response->assertOk();
});

it('rejects unauthorized users', function () {
    $user  = User::factory()->create();
    $order = Order::factory()->create(); // different owner

    $this->actingAs($user);

    $response = $this->postJson('/broadcasting/auth', [
        'channel_name' => "private-orders.{$order->id}",
        'socket_id'    => '123.456',
    ]);

    $response->assertForbidden();
});

```

No WebSocket connection is needed — the auth endpoint is plain HTTP.

### Key Takeaways

- Return an array from `join()` to enable presence semantics; return `false` to deny.
- Override the broadcasting auth middleware to match your app's guard (`auth:sanctum`, `auth:api`, etc.).
- Pass `Authorization` headers in the Echo `auth` config for token-based clients.
- Enable Redis scaling when running multiple Reverb workers to share presence state.
- Test channel authorization over HTTP — no live WebSocket required.

 Found this useful?

          [  ](https://twitter.com/intent/tweet?url=https%3A%2F%2Fmsaied.com%2Farticles%2Flaravel-broadcasting-with-reverb-private-channels-presence-and-auth-guards&text=Laravel+Broadcasting+with+Reverb%3A+Private+Channels%2C+Presence%2C+and+Auth+Guards) [  ](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fmsaied.com%2Farticles%2Flaravel-broadcasting-with-reverb-private-channels-presence-and-auth-guards) 

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

  3 questions  

     Q01  Why does my presence channel show no members when running multiple Reverb workers?        Reverb stores presence state in the worker process by default. With multiple workers, each process has its own member list. Enable Redis-backed scaling via REVERB_SCALING_ENABLED=true and configure the shared Redis connection so all workers share a single presence store. 

      Q02  How do I use a Sanctum token instead of session cookies for broadcasting auth?        Override the broadcasting auth route middleware in BroadcastServiceProvider: Broadcast::routes(['middleware' =&gt; ['auth:sanctum']]). Then pass the token as an Authorization header in the Echo auth.headers config on the frontend. 

      Q03  What is the difference between a private and a presence channel in Reverb?        Both require authorization. A private channel returns true/false from the channel class. A presence channel returns an array of member metadata, which Reverb uses to track who is currently subscribed and expose joining/leaving events to all members. 

  Continue reading

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

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

 [ ![Cursor Pagination, Chunked Iteration, and Lazy Collections at Scale in Laravel](https://cdn.msaied.com/415/eb2d62822119280148e092d25b36c6ae.png) laravel eloquent performance 

### Cursor Pagination, Chunked Iteration, and Lazy Collections at Scale in Laravel

Offset pagination breaks under large datasets. Learn how cursor pagination, chunked iteration, and lazy collec...

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

 12 Jul 2026     4 min read  

  Read    

 ](https://msaied.com/articles/cursor-pagination-chunked-iteration-and-lazy-collections-at-scale-in-laravel-2) [ ![Job Batching, Chaining, and Rate-Limited Middleware for Laravel Queues](https://cdn.msaied.com/414/154bd945ee1677f140cd1ea4132e5b66.png) laravel queues jobs 

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

Go beyond basic dispatch: learn how to compose Laravel job batches, build reliable chains with catch callbacks...

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

 12 Jul 2026     3 min read  

  Read    

 ](https://msaied.com/articles/job-batching-chaining-and-rate-limited-middleware-for-laravel-queues) [ ![Laravel Observers vs. Model Events: Choosing the Right Hook for Side Effects](https://cdn.msaied.com/413/ec9d48bb1167db4a2ec2e0784f3be002.png) laravel eloquent observers 

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

Model events and observers both react to Eloquent lifecycle moments, but picking the wrong one creates hidden...

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

 11 Jul 2026     3 min read  

  Read    

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

   [  ![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)
