Laravel Reverb: Private Channels &amp; Auth Guards | Mohamed Said       [Skip to content](#main)  [ ![](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png) Mohamed SaidLaravel Backend Engineer ](https://www.msaied.com/public) - [Home](https://www.msaied.com/public)
- [Projects](https://www.msaied.com/public/projects)
- [Articles](https://www.msaied.com/public/articles)
- [Certificates](https://www.msaied.com/public/certificates)
- [About](https://www.msaied.com/public#about)

           [  Contact](https://www.msaied.com/public#contact) Menu 

Menu
----

Close 

 - [HomeStart here](https://www.msaied.com/public)
- [ProjectsCase studies](https://www.msaied.com/public/projects)
- [ArticlesEngineering notes](https://www.msaied.com/public/articles)
- [CertificatesCredentials](https://www.msaied.com/public/certificates)
- [AboutHow I work](https://www.msaied.com/public#about)
- [ContactGet in touch](https://www.msaied.com/public#contact)

  [Start a conversation](https://www.msaied.com/public#contact) [WhatsApp](https://wa.me/201094619204) [Email](mailto:hello@msaied.com) 

 1. [Home](https://www.msaied.com/public)
2. /
3. [Articles](https://www.msaied.com/public/articles)
4. /
5. Laravel Broadcasting with Reverb: Private Channels, Presence, and Auth Guards

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

 Go beyond the basics of Laravel Reverb. Learn how to secure private and presence channels, wire up custom auth guards, and avoid the subtle pitfalls that bite teams in production.

 ![](https://cdn.msaied.com/01M22N44A70A5MC2S599JP0MPH.webp) [Mohamed Said](https://www.msaied.com/public#person) Published 12 Jul 2026 · Updated 12 Jul 2026 · 4 min read

ShareCopy linkCopied

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

  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 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.

- [laravel](https://www.msaied.com/public/articles?search=laravel)
- [reverb](https://www.msaied.com/public/articles?search=reverb)
- [broadcasting](https://www.msaied.com/public/articles?search=broadcasting)
- [websockets](https://www.msaied.com/public/articles?search=websockets)
- [real-time](https://www.msaied.com/public/articles?search=real-time)

 Frequently asked questions 
---------------------------

  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.

   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.

   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.

   ![Mohamed Said](https://cdn.msaied.com/01M22N44A70A5MC2S599JP0MPH.webp)About the author
----------------

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

[About](https://www.msaied.com/public#about) [GitHub ↗](https://github.com/EG-Mohamed) [LinkedIn ↗](https://www.linkedin.com/in/msaiedm/) [WhatsApp ↗](https://wa.me/201094619204) [Email Address ↗](mailto:hello@msaied.com) [My CV ↗](https://drive.google.com/file/u/0/d/1MF20IPRJyzfy32mhEutjL5EpSls0w2Q8/view)  

   [Previous articleCursor Pagination, Chunked Iteration, and Lazy Collections at Scale in Laravel](https://www.msaied.com/public/articles/cursor-pagination-chunked-iteration-and-lazy-collections-at-scale-in-laravel-2) [Next articleService Container Deep Dive: Contextual Binding, Tagging, and Method Injection](https://www.msaied.com/public/articles/service-container-deep-dive-contextual-binding-tagging-and-method-injection)  

   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)

 ###  Have a technical challenge?

 Tell me what you’re building. I reply within two working days.

[Start a conversation](https://www.msaied.com/public#contact) 

   Related articles
-----------------

 [ ![](https://cdn.msaied.com/740/cce86edc21eddcbdd2f2454fadaf9c70.png)  · 3 min read### The Pipeline Pattern in Laravel: Custom Pipelines Beyond Middleware

5 Oct 2026 ](https://www.msaied.com/public/articles/the-pipeline-pattern-in-laravel-custom-pipelines-beyond-middleware-1) [ ![](https://cdn.msaied.com/739/2d6897fdcdcf090613f96f72a64b8a78.png)  · 4 min read### MySQL Full-Text Search in Laravel: Indexes, Relevance Scoring, and Boolean Mode

4 Oct 2026 ](https://www.msaied.com/public/articles/mysql-full-text-search-in-laravel-indexes-relevance-scoring-and-boolean-mode) [ ![](https://cdn.msaied.com/738/073696a3fefe18bec825beec5ac658f5.png)  · 4 min read### Laravel Queue Rate-Limited Middleware: Throttling Jobs Without Losing Work

4 Oct 2026 ](https://www.msaied.com/public/articles/laravel-queue-rate-limited-middleware-throttling-jobs-without-losing-work) 

  Have a technical challenge?
----------------------------

Tell me what you’re building. I reply within two working days.

 [Discuss your project ↗](https://www.msaied.com/public#contact) 

  © 2026 Mohamed Said · Built with Laravel, meant to last.Senior Backend Engineer specializing in Laravel, scalable SaaS platforms, APIs, and cloud infrastructure. I build secure, high-performance web applications that help businesses grow.

 - [Home](https://www.msaied.com/public)
- [Articles](https://www.msaied.com/public/articles)
- [Certificates](https://www.msaied.com/public/certificates)
- [GitHub](https://github.com/EG-Mohamed)
- [LinkedIn](https://www.linkedin.com/in/msaiedm/)
- [WhatsApp](https://wa.me/201094619204)
- [Email Address](mailto:hello@msaied.com)
- [My CV](https://drive.google.com/file/u/0/d/1MF20IPRJyzfy32mhEutjL5EpSls0w2Q8/view)
- [Sitemap](https://www.msaied.com/public/sitemap.xml)
