Laravel & Backend8 min read

How to Implement Role-Based Access Control (RBAC) in Laravel

Md Shahed Alam
Md Shahed Alam
March 25, 2025
How to Implement Role-Based Access Control (RBAC) in Laravel

Every app I have built eventually needed the same thing: some users can do everything, some can only read, some can edit but not delete. This is role-based access control, and it is one of those things that is much easier to add early than to bolt on later.

The idea is simple. Instead of giving permissions directly to users, you create roles. A role is just a label — "admin", "editor", "viewer". You attach permissions to roles, then assign roles to users.

The easiest way: Spatie's permission package

Building RBAC from scratch is possible, but spatie/laravel-permission does it better than most people would on their own. It is well-tested, actively maintained, and used by thousands of projects.

bash
composer require spatie/laravel-permission
php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider"
php artisan migrate

Add the trait to your User model:

php
use Spatie\Permission\Traits\HasRoles;

class User extends Authenticatable {
    use HasRoles;
}

Setting up roles and permissions

Do this in a seeder so you can recreate it on any environment:

php
$adminRole = Role::create(['name' => 'admin']);
$editorRole = Role::create(['name' => 'editor']);

Permission::create(['name' => 'create post']);
Permission::create(['name' => 'edit post']);
Permission::create(['name' => 'delete post']);

$adminRole->givePermissionTo(['create post', 'edit post', 'delete post']);
$editorRole->givePermissionTo(['create post', 'edit post']);

Assigning roles to users

php
$user->assignRole('editor');

// Check what roles a user has
$user->hasRole('admin'); // true or false
$user->getRoleNames(); // ['editor']

Checking permissions in your code

In controllers:

php
if ($request->user()->cannot('delete post')) {
    abort(403, 'You do not have permission to delete posts.');
}

In Blade templates:

php
@can('delete post')
    <button class="btn-danger">Delete</button>
@endcan

Using middleware on routes:

php
Route::delete('/posts/{post}', [PostController::class, 'destroy'])
    ->middleware('permission:delete post');

A tip about performance

The package caches permissions automatically. But if you assign or remove roles in tests or seeders, you might need to clear the cache:

php
app()[\Spatie\Permission\PermissionRegistrar::class]->forgetCachedPermissions();

Do you always need a package?

Not always. If your app only has two roles — admin and regular user — a simple is_admin boolean on the users table might be all you need. Do not add complexity you do not need.

But if you have more than three roles, or if permissions change frequently, the package is worth it.

LaravelRBACAuthorizationSecurity

Ready to build something great?

Let's talk about your project. We will give you honest advice, a clear plan, and a fair price. No pressure, no sales pitch.

Free consultation
No commitment required
Response within 24 hours