Skip to main content
When a package broadcasts real-time events, separate defining the channel name from the check that decides who may join. A channel a package registers in boot() can be overwritten by the application’s routes/channels.php if both use the same name. Understanding the registration and evaluation order helps avoid bugs during maintenance. This page references the Laravel official Broadcasting docs and the implementation in the latest release v13.42.0 used for verification. For how to send events, see Broadcasting. For how providers are loaded, see Package Discovery.

How channel authorization works

When a client subscribes to a private channel, it sends a request to /broadcasting/auth. BroadcastController::authenticate() hands off to Broadcast::auth(), and the Broadcaster evaluates the registered callbacks in order. The evaluation rules are:
  • If a callback returns false, an AccessDeniedHttpException is thrown immediately.
  • If a callback returns a truthy value such as true, authorization succeeds at that point.
  • If a callback returns a falsy value such as null, evaluation moves on to the next registered callback. If none grants access, an AccessDeniedHttpException is thrown at the end.
The Pusher and Reverb drivers strip the private- and presence- prefixes before authorization. For that reason, do not include the prefix in the channel names you register.

Registering a channel in a package

As an example, a hypothetical Acme\Orders package broadcasts order status changes. The channel name is acme.orders.{order}, and only the order’s owner may subscribe. In the package’s ServiceProvider, call Broadcast::channel() inside boot(). Delegate the decision to a class inside the package.
The first argument of join() receives the user at authorization time. The remaining arguments receive the values of the {...} placeholders in the channel name. If the parameter name matches {order} and the Order $order type is a subclass of UrlRoutable, route model binding applies.
The $callback passed to Broadcast::channel() can be a callable or a class name whose join() method handles the check. For a class name, Broadcaster::normalizeChannelHandlerToCallable() builds the instance from the container and then calls join().

Overriding in the application

The file passed to withBroadcasting() (usually routes/channels.php) is loaded inside a booted callback that withBroadcasting() registers. The booted callbacks run after every service provider’s boot() has finished, so the package’s boot() registration happens first. Broadcaster::channel() stores callbacks in an internal array keyed by channel name. If the application registers the same name, the second registration replaces the package’s. Laravel does not raise an error for a duplicate name. To avoid overrides, make the channel name unique. For example, a package-specific prefix such as acme.orders.{order} lowers the chance that the application registers the same name. Channel names are a public contract with clients. Once chosen, do not change them. Changing a name prevents existing clients from subscribing.
A channel registered later with the same name silently takes precedence. php artisan channel:list shows each channel name and its resolver (a class name or Closure), so you can check which registration is in effect.

Channel options and guards

The third argument to Broadcast::channel(), $options, is stored as per-channel configuration. Setting guards makes the authorization try the listed guards in order.
If guards is omitted, the request’s default user ($request->user()) is used for authorization. When guards is set, $request->user($guard) is called for each guard in order, and the first user returned is used. If a package fixes a guard name, the application’s guard configuration can cause authorization to fail. Expose the guard names as configuration so the application can choose them.

Verifying channel registration in tests

Registered channels can be retrieved from the driver with getChannels(), which returns a Collection. The keys are the channel names themselves.
Verify authorization results with an HTTP test against /broadcasting/auth. The null and log drivers return nothing from auth(), so they cannot be used for this test. Channels are registered on the default driver when the application boots, so set BROADCAST_CONNECTION to reverb or pusher in a test configuration such as phpunit.xml before sending the authenticated request.
The test app must register the /broadcasting/auth route. Broadcast::routes() registers it, and BroadcastManager::channelRoutes() only delegates to routes(). If the routes are cached, routes() does nothing.

Maintenance notes

  • Channel names are a public contract. Renaming them prevents existing clients from subscribing.
  • Class-based channels are resolved from the Container. Make sure constructor dependencies can be resolved from the container.

Summary

A package’s channel authorization works when it registers Broadcast::channel() in boot(). If the application’s routes/channels.php registers the same name later, the package’s authorization is replaced. Using a prefixed channel name, separating the check into a class, and verifying /broadcasting/auth results with HTTP tests keeps the package easier to maintain.

Primary sources

Last modified on November 14, 2026