403 Forbidden on /broadcasting/auth with Sanctum and custom API prefix #55901
Replies: 2 comments
-
Beta Was this translation helpful? Give feedback.
-
Hi 👋, I faced this same issue and solved it by aligning the authentication method in ✅ Root Cause:When you use Since you're sending a Bearer token in the header (not using Laravel session/cookie), Sanctum middleware might not detect the user correctly, and 🛠 Solution:1. Update your
|
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Laravel Version
12.10.2
PHP Version
8.3.11
Database Driver & Version
No response
Description
When using Sanctum with API token authentication and configuring
Broadcast::routes()
with a custom prefix (e.g.,api
) and middleware['auth:sanctum']
, the/api/broadcasting/auth
route returns a 403AccessDeniedHttpException
.Even with valid tokens and a verified user (via
Auth::check()
), access is still denied.The route is correctly listed via
php artisan route:list
:Steps To Reproduce
POST | api/broadcasting/auth | ... Illuminate\Broadcasting\BroadcastController@authenticate
`// Enhanced pusherSetup.tsx for third-party Pusher
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';
import { API_BASE_URL } from '@/constants/config';
// Disable Pusher logs for production
// Pusher.logToConsole = DEV; // Only log in development
// Make Pusher available on window
// @ts-ignore
window.Pusher = Pusher;
// Pusher Configuration - Replace with your Pusher app credentials
const PUSHER_APP_KEY = ''; //
const PUSHER_CLUSTER = 'us2'; // Your Pusher cluster (e.g., 'us2', 'eu', 'ap3')
const createEcho = (userToken: string): Echo | null => {
console.log(
Creating Echo instance with Pusher and token: ${userToken}
);if (!userToken) {
console.error('User token is required to create Echo instance');
return null;
}
try {
return new Echo({
broadcaster: 'pusher', // Changed from 'reverb' to 'pusher'
key: PUSHER_APP_KEY,
cluster: PUSHER_CLUSTER,
forceTLS: true, // Always use TLS with Pusher
encrypted: true, // Always encrypt with Pusher
} catch (error) {
console.error('Error creating Echo instance:', error);
return null;
}
};
// Alternative simplified configuration if you don't need custom auth
export const createEchoSimple = (userToken: string): Echo | null => {
if (!userToken) {
console.error('User token is required to create Echo instance');
return null;
}
try {
return new Echo({
broadcaster: 'pusher',
key: PUSHER_APP_KEY,
cluster: PUSHER_CLUSTER,
forceTLS: true,
auth: {
headers: {
'Authorization':
Bearer ${userToken}
,}
}
});
} catch (error) {
console.error('Error creating simple Echo instance:', error);
return null;
}
};
// Default export
export default createEcho;`
Register broadcast routes like this
`<?php
// app/Providers/BroadcastServiceProvider.php
namespace App\Providers;
use Illuminate\Support\Facades\Broadcast;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\ServiceProvider;
class BroadcastServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*/
public function boot(): void
{
}
const setupReverb = async (userToken: any) => {
try {
console.log('Setting up Pusher connection...');
};
routes/channel.php
<?phpuse App\Models\Conversation;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Broadcast;
use Illuminate\Support\Facades\Log;
Broadcast::channel('App.Models.User.{id}', function ($user, $id) {
Auth::check();
return (int) $user->id === (int) $id;
});
// Authorize conversation channels
Broadcast::channel('conversation.{conversationId}', function ($user, $conversationId) {
// Check if user is participant in this conversation
Auth::check();
});
// Optional: Presence channel for online status
Broadcast::channel('conversation-presence.{conversationId}', function ($user, $conversationId) {
$conversation = Conversation::find($conversationId);
});`
Beta Was this translation helpful? Give feedback.
All reactions