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

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

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

  [ home ](https://www.msaied.com)    [ articles ](https://www.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%2Fwww.msaied.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%2Fwww.msaied.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://www.msaied.com/articles) 

 [ ![Laravel queue:work Now Prints Why the Worker Stopped](https://cdn.msaied.com/629/bed93940d17b932032d64cee2e32d333.png) Laravel Queue Laravel 13.30 

### Laravel queue:work Now Prints Why the Worker Stopped

Laravel 13.30 adds a stop-reason line to queue:work output. Workers now print why they exited—memory limit, re...

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

 3 Sep 2026     3 min read  

  Read    

 ](https://www.msaied.com/articles/laravel-queuework-now-prints-why-the-worker-stopped) [ ![The Laracon Archive: 626 Talks, 287 Speakers, and 14 Years of Laravel History](https://cdn.msaied.com/628/13d8d0cef5fb083813df134cc253bb1b.png) laracon laravel community 

### The Laracon Archive: 626 Talks, 287 Speakers, and 14 Years of Laravel History

The Laracon Archive is a community-built, searchable index of every recorded Laracon talk — 626 talks from 287...

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

 3 Sep 2026     3 min read  

  Read    

 ](https://www.msaied.com/articles/the-laracon-archive-626-talks-287-speakers-and-14-years-of-laravel-history) [ ![Semantic Memory or Just Markdown? How Laravel Boost Manages AI Agent Project Rules](https://cdn.msaied.com/627/b162933f96fd615f3165bfe167816018.png) Laravel Boost AI Agents Context Engineering 

### Semantic Memory or Just Markdown? How Laravel Boost Manages AI Agent Project Rules

Laravel Boost tried semantic search with embeddings and a vector index to give AI coding agents project memory...

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

 3 Sep 2026     4 min read  

  Read    

 ](https://www.msaied.com/articles/semantic-memory-or-just-markdown-how-laravel-boost-manages-ai-agent-project-rules) 

   [  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png)   Mohamed Said Laravel Backend Engineer  ](https://www.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://www.msaied.com)
- [Projects](https://www.msaied.com/projects)
- [Articles](https://www.msaied.com/articles)
- [Certificates](https://www.msaied.com/certificates)
- [Contact](https://www.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)
