In most modern web applications, user roles are essential. Whether it’s an admin managing the platform or a basic user accessing restricted resources — Role-Based Access Control (RBAC) is the go-to strategy.

Laravel, being the opinionated framework it is, gives us two powerful tools to implement authorization logic: Gates and Policies. In this post, we’ll walk through setting up RBAC using both.

What is RBAC?

RBAC is a security paradigm that restricts system access based on roles assigned to users. Each role has specific permissions, and those permissions determine what the user can or cannot do.

For example:

  • Admin → Can manage users, edit posts, delete comments
  • Editor → Can edit posts but not delete them
  • User → Can only read content

Laravel doesn’t enforce RBAC by default — but it gives us the tools to build it ourselves using Gates and Policies.

Step 1: Setting Up Roles in the Laravel

Let’s assume you already have a Laravel app with a users table.

Add a role column to your users table

php artisan make:migration add_role_to_users_table --table=users

Then edit the migration file:

// database/migrations/xxxx_xx_xx_add_role_to_users_table.php

public function up()
{
    Schema::table('users', function (Blueprint $table) {
        $table->string('role')->default('user'); // values: user, editor, admin
    });
}

Run the migration:

php artisan migrate

Step 2: Using Gates for Simple RBAC

Gates are perfect for quick, role-based checks.

Define Gates in AuthServiceProvider

// app/Providers/AuthServiceProvider.php

use Illuminate\Support\Facades\Gate;

public function boot()
{
    $this->registerPolicies();

    Gate::define('access-admin', function ($user) {
        return $user->role === 'admin';
    });

    Gate::define('edit-posts', function ($user) {
        return in_array($user->role, ['admin', 'editor']);
    });
}

Step 3: Use Gates in Controller or Blade

// In Controller
if (Gate::denies('access-admin')) {
    abort(403);
}
{{-- In Blade --}}
@can('edit-posts')
    <a href="/posts/edit">Edit Post</a>
@endcan

That’s it, you’ve now added basic RBAC using Gates.

When to Use Policies?

Policies are like mini-classes tied to a specific model, perfect for fine-grained access control.

Let’s walk through using Policies for managing posts.

Step-by-Step: Policies for Post Permissions

Step 1: Create a Policy

php artisan make:policy PostPolicy --model=Post

This will generate a policy with methods like view, update, delete, etc.

Step 2: Define Role-Based Rules

// app/Policies/PostPolicy.php

public function update(User $user, Post $post)
{
    return $user->id === $post->user_id || $user->role === 'admin';
}

public function delete(User $user, Post $post)
{
    return $user->role === 'admin';
}

Step 3: Register the Policy

Laravel does this automatically when using --model=Post, but double-check:

// app/Providers/AuthServiceProvider.php

protected $policies = [
    Post::class => PostPolicy::class,
];

Step 4: Use in Controller

public function update(Request $request, Post $post)
{
    $this->authorize('update', $post);

    // Update logic here...
}

Or in Blade:

@can('delete', $post)
    <form method="POST" action="{{ route('posts.destroy', $post) }}">
        @csrf
        @method('DELETE')
        <button>Delete</button>
    </form>
@endcan

Combining Gates + Policies + Middleware

You can combine everything:

// app/Http/Middleware/AdminMiddleware.php

public function handle($request, Closure $next)
{
    if (auth()->user()?->role !== 'admin') {
        abort(403, 'Unauthorized');
    }

    return $next($request);
}

Then use it on your routes:

Route::middleware(['auth', 'admin'])->group(function () {
    Route::resource('users', UserController::class);
});

Laravel doesn’t dictate how to implement RBAC, it just empowers you with the tools. Whether you use Gates for quick checks, Policies for model-specific rules, or a dedicated roles/permissions system (like Spatie’s Laravel-Permission package), you can build a secure, maintainable access system in your Laravel apps.

Similar Posts