Security Tip: Consider All Routes, Not Just Web!

[Tip #125] routes/web.php is boring and reliable, and routes/api.php is fancy, but have you forgotten one?

Security Tip: Consider All Routes, Not Just Web!

A common pattern I see all the time is an is_active flag on a User record, with matching EnsureUserIsActive middleware on the web route or auth route group inside routes/web.php.

As you'd expect, this is used to prevent a User who has been deactivated from accessing the application. It's simple to implement, with minimal overhead in the code, and typically just works.

However...

The routes inside routes/web.php aren't the only places where the user can interact with your application. There are typically two more you need to consider too:

  1. API routes.
  2. Broadcast channels.

The API routes inside routes/api.php are just fancy versions of what you've got inside routes/web.php. They even have their own Middleware stack too, so I'll often find EnsureUserIsActive has been added where it's needed, so the active user is properly checked.

However, Broadcast channels don't have their own middleware, exist in the strange alternate universe of routes/channels.php, and all you've got to work with is this:

Broadcast::channel('App.Models.User.{id}', function ($user, $id) {
    return (int) $user->id === (int) $id;
});

Default user channel auth callback.

The channel name often changes to something simpler, like user.{id}, but the conditional - that's usually all I find here.

Notice what's missing?

The is_active flag is being completely ignored! This means that a user account can be deactivated and kicked out of the UI and the API, but still subscribe and listen to broadcast messages.

What this exposes depends very much on what you send through your broadcast messages. However, there is the potential for significant information leakage in real-time applications that broadcast a lot of sensitive information and rely on flags like is_active to control user access.

In summary...

Ultimately, my point here is that you need to consider all routes a user can interact with your application through, and ensure that any access control measures, like is_active flags, are checked across all of them.

And don't forget about the humble routes/channels.php, it's just as important as routes/web.php and routes/api.php!


If you found this security tip useful? 👍
Subscribe now to get weekly Security Tips straight to your inbox, filled with practical, actionable advice to help you build safer apps.

Want to learn more? 🤓
Upgrade to a Premium Subscription for exclusive monthly In Depth articles, or support my work with a one-off tip! Your support directly funds my security work in the Laravel community. 🥰

Need a second set of eyes on your code?
Book in a
Laravel Security Audit and Penetration Test today! I also offer budget-friendly Security Reviews too.

Finally, connect with me on Bluesky, or other socials, and check out Practical Laravel Security, my interactive course designed to boost your Laravel security skills.