How to use correctly Super Admin's role in Laravel Spatie

Stefan Bogdanescu

Founder & Senior Architect · 2026-06-29

Laravel Company

Mastering Role Management in Laravel with Spatie Permissions: Gates vs. Middleware

As a senior developer working with Laravel, understanding how to implement robust authorization is paramount. When leveraging powerful packages like Spatie's permission system, developers often run into nuances regarding where and how to check user roles. The confusion between using the Gate::before() method and route middleware is very common. This post will break down the correct way to manage Super Admin roles and permissions effectively in your Laravel application.

The Authorization Landscape: Gates vs. Middleware

The core of your question lies in distinguishing between two primary mechanisms Laravel offers for access control: Gates (which are based on authorization logic) and Middleware (which is request filtering).

Understanding Gate::before()

You attempted to use the Gate::before() method:

Gate::before(function ($user, $ability) {
    return $user->hasRole('Super Admin') ? true : null;
});

While Gate::before() is a powerful tool for inspecting permissions before an action is executed within the context of Gates and Policies, it is generally better suited for complex, dynamic authorization logic tied to specific model operations (e.g., "Can this user edit this specific post?"). When trying to enforce broad role checks across entire routes or controllers, relying solely on Gate::before() often leads to conflicts with the standard middleware pipeline.

The Power of Route Middleware for Role Checks

The successful approach you observed—using route-level middleware like role:Super Admin|Provider—is the correct and most idiomatic way to handle broad access control based on roles or permissions in Laravel.

Middleware operates at a higher level, acting as a gatekeeper for entire routes or groups of routes before the request even hits your controller logic. Spatie integrates seamlessly with this system, allowing you to define these role checks directly in your web.php or api.php files. This approach keeps route configuration clean and separates routing concerns from business logic, aligning perfectly with Laravel's philosophy of separation of concerns—a core principle shared by frameworks like Laravel itself.

Implementing Role-Based Access Control Correctly

For defining which routes a 'Super Admin' can access, middleware is the superior choice:

// In web.php or api.php
Route::group(['middleware' => ['auth:api', 'role:Super Admin|Provider']], function () {
    // These routes are only accessible if the authenticated user has the 'Super Admin' OR 'Provider' role.
    Route::get('/providers', [ProviderController::class, 'index']);
    Route::post('/providers', [ProviderController::class, 'store']);
});

This method is cleaner because it leverages Spatie’s built-in permission system directly within the routing layer. It ensures that if a user lacks the necessary role, the request is immediately rejected before any controller method is executed. This is an excellent pattern to follow when building scalable applications, similar to how robust architecture is encouraged in the Laravel ecosystem.

Handling Controller Logic (The ProviderController Example)

Your concern regarding your ProviderController middleware setup is valid. Attempting to apply permission checks within the controller using $this->middleware('permission:...') inside the constructor can be overly complex and sometimes redundant, especially when route-level protection is already in place.

If you have applied the role/permission check at the route level (as shown above), the controller methods should focus purely on executing the requested business logic. You can use the $this->authorize() helper or the $user->hasRole() method inside the controller methods for fine-grained checks, ensuring that your application logic is explicitly aware of authorization requirements.

Best Practice Summary:

  1. Route Definition (The Gatekeeper): Use route middleware (role:name or permission:name) to filter access at the entry point. This is where you define who can reach a resource.
  2. Controller Logic (The Executor): Use methods like $user->hasRole('Super Admin') inside controller methods for fine-grained checks on specific data manipulations.

By separating these concerns, you create a more maintainable and scalable system. Remember, leveraging the core strengths of Laravel, such as its robust request lifecycle management, is key to building solid applications. For further deep dives into structuring your application architecture, explore resources from laravelcompany.com.

Conclusion

In summary, for managing Super Admin roles and permissions with Spatie: rely on route middleware for access control and use the underlying Gate system for object-level authorization within your business logic. Your instinct to check permissions was correct; the key is choosing the right tool for the job. By using route middleware as demonstrated, you establish a clear, efficient, and highly secure authorization layer for your Laravel application.