Overview

Secure WebSockets with Authentication in Laravel 11 (Reverb & Laravel Echo)

By default, Laravel Reverb allows public and private channels. To secure WebSockets, we need authenticated private channels.


Step 1: Enable Laravel Authentication Middleware

Ensure your Laravel app has authentication. If you haven’t set it up, run:

php artisan make:auth  # For Laravel Breeze / Jetstream users

For API authentication, use Laravel Sanctum:

composer require laravel/sanctum php artisan sanctum:install

Then, add Sanctum’s middleware in app/Http/Kernel.php:

'api' => [
    \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
    'throttle:api',
    \Illuminate\Routing\Middleware\SubstituteBindings::class,
],

Step 2: Define Private Channel Authorization

Modify routes/channels.php to authorize users before they subscribe to WebSocket channels.

use Illuminate\Support\Facades\Broadcast;
Broadcast::channel('notifications', function ($user) {
    return $user != null; // Only authenticated users can join 
});

This ensures that only logged-in users can access the notifications channel.


Step 3: Configure Laravel Echo with Authentication

Modify resources/js/bootstrap.js to include authentication:

import Echo from "laravel-echo"; import Pusher from "pusher-js";
window.Echo = new Echo({
    broadcaster: "pusher",
    key: "anykey", // Not required for Reverb
    wsHost: window.location.hostname,
    wsPort: 6001,
    forceTLS: false,
    disableStats: true,
    authEndpoint: "/broadcasting/auth",  // Laravel's default auth endpoint
    auth: {
        headers: {
            Authorization: `Bearer ${localStorage.getItem("auth_token")}`, // Use stored token for API authentication
            "X-CSRF-TOKEN": document.querySelector('meta[name="csrf-token"]').getAttribute("content"),
        },
    },
});

Step 4: Modify Event to Use Private Channels

Modify app/Events/NewNotification.php:

use Illuminate\Broadcasting\PrivateChannel;
public function broadcastOn() {
    return new PrivateChannel('notifications'); // Private channel 
}

Step 5: Send Notifications Only to Authenticated Users

Modify routes/web.php to send notifications to logged-in users:

use App\Events\NewNotification; use Illuminate\Support\Facades\Route;
Route::middleware('auth:sanctum')->get('/send-notification', function () {
    broadcast(new NewNotification("Hello, authenticated user!"));
    return response()->json(['message' => 'Notification sent']); 
});

Step 6: Listen for Authenticated Notifications in JavaScript

Modify your JS frontend:

window.Echo.private("notifications")
    .listen(".new-notification", (e) => {
        console.log("New Notification:", e.message);
    });

Step 7: Restart Everything

Run these commands:

php artisan cache:clear
php artisan config:clear
php artisan reverb:start
npm run dev
php artisan serve

✅ Final Security Check

  1. Login as an authenticated user

  2. Visit:

    http://127.0.0.1:8000/send-notification

  3. Check browser console (F12 > Console) → Should see "New Notification: Hello, authenticated user!"

  4. If not logged in, WebSocket should NOT connect


🔥 Final Security Summary

Only logged-in users can access WebSockets
Laravel Echo now authenticates requests
Private channels require authorization
Sanctum protects API requests

This setup prevents unauthorized users from receiving notifications. 🎯

add presence channels (to show online users)? 🚀