Laravel 12 Roles and Permissions (Without Any Packages) – A Complete Guide

Author

Kritim Yantra

Mar 27, 2025

Laravel 12 Roles and Permissions (Without Any Packages) – A Complete Guide

Managing user roles and permissions is essential for controlling access in web applications. While packages like Spatie Laravel-Permission exist, you can easily implement this in pure Laravel without external dependencies.

In this guide, we’ll cover:
Database Setup for Roles & Permissions
Assigning Roles to Users
Checking Permissions in Controllers & Views
Middleware for Role-Based Access

Let’s build a role-based system from scratch!


1. Why Build Roles & Permissions Without a Package?

🔹 Full control over the logic
🔹 No dependency on third-party packages
🔹 Lightweight & customizable
🔹 Great for learning Laravel’s core features


2. Database Structure

We’ll use 4 tables:

  1. users (Default Laravel users table)
  2. roles (Admin, Editor, User)
  3. permissions (create-post, edit-post, delete-post)
  4. role_permission (Pivot table linking roles and permissions)

Step 1: Create Migrations

Run these commands:

php artisan make:migration create_roles_table
php artisan make:migration create_permissions_table
php artisan make:migration create_role_permission_table

a) roles Table Migration

Schema::create('roles', function (Blueprint $table) {
    $table->id();
    $table->string('name'); // admin, editor, user
    $table->timestamps();
});

b) permissions Table Migration

Schema::create('permissions', function (Blueprint $table) {
    $table->id();
    $table->string('name'); // create-post, edit-post, delete-post
    $table->timestamps();
});

c) role_permission Pivot Table

Schema::create('role_permission', function (Blueprint $table) {
    $table->foreignId('role_id')->constrained();
    $table->foreignId('permission_id')->constrained();
    $table->primary(['role_id', 'permission_id']);
});

d) Add role_id to users Table

php artisan make:migration add_role_id_to_users_table
Schema::table('users', function (Blueprint $table) {
    $table->foreignId('role_id')->default(3)->constrained(); // Default role: 'user'
});

Run migrations:

php artisan migrate

3. Setting Up Models & Relationships

a) User Model

// app/Models/User.php
public function role()
{
    return $this->belongsTo(Role::class);
}

public function hasPermission($permissionName)
{
    return $this->role->permissions()->where('name', $permissionName)->exists();
}

b) Role Model

// app/Models/Role.php
public function permissions()
{
    return $this->belongsToMany(Permission::class);
}

c) Permission Model

// app/Models/Permission.php
public function roles()
{
    return $this->belongsToMany(Role::class);
}

4. Seeding Roles & Permissions

Let’s populate the database with sample data.

Create a Seeder

php artisan make:seeder RolePermissionSeeder
// database/seeders/RolePermissionSeeder.php
public function run()
{
    // Create Roles
    $admin = Role::create(['name' => 'admin']);
    $editor = Role::create(['name' => 'editor']);
    $user = Role::create(['name' => 'user']);

    // Create Permissions
    $createPost = Permission::create(['name' => 'create-post']);
    $editPost = Permission::create(['name' => 'edit-post']);
    $deletePost = Permission::create(['name' => 'delete-post']);

    // Assign Permissions to Roles
    $admin->permissions()->attach([$createPost->id, $editPost->id, $deletePost->id]);
    $editor->permissions()->attach([$createPost->id, $editPost->id]);
    $user->permissions()->attach([$createPost->id]);
}

Run the seeder:

php artisan db:seed --class=RolePermissionSeeder

5. Checking Permissions in Controllers

Example: Restrict Post Creation to Users with Permission

// app/Http/Controllers/PostController.php
public function create()
{
    if (!auth()->user()->hasPermission('create-post')) {
        abort(403, 'Unauthorized action.');
    }
    return view('posts.create');
}

6. Middleware for Role-Based Access

Step 1: Create Middleware

php artisan make:middleware CheckRole

Step 2: Define Logic

// app/Http/Middleware/CheckRole.php
public function handle($request, Closure $next, $role)
{
    if (auth()->check() && auth()->user()->role->name === $role) {
        return $next($request);
    }
    abort(403, 'Access Denied');
}

Step 3: Register Middleware

Add this tobootstrap/app.php:

->withMiddleware(function (Middleware $middleware) {
        $middleware->alias([
            'role' => \App\Http\Middleware\CheckRole::class,
        ]);
    })

Step 4: Protect Routes

Route::get('/admin/dashboard', function () {
    return view('admin.dashboard');
})->middleware('role:admin');

7. Checking Permissions in Blade Views

@if(auth()->user()->hasPermission('edit-post'))
    <a href="/posts/{{ $post->id }}/edit">Edit Post</a>
@endif

8. Assigning Roles to Users

// Make a user an admin
$user = User::find(1);
$user->role_id = 1; // admin role
$user->save();

9. Best Practices

Use caching for permissions to reduce database queries.
Avoid hardcoding role/permission names (use constants).
Test permissions thoroughly with unit tests.


Conclusion

You’ve just built a full role-permission system in Laravel without any packages!

🔹 Database Setup → Roles, Permissions, Pivot Tables
🔹 Models & RelationshipsUser, Role, Permission
🔹 Middleware & Controllers → Restrict access
🔹 Blade Checks → Show/hide UI elements

🚀 Now go ahead and implement this in your Laravel app!

LIVE MENTORSHIP ONLY 5 SPOTS

Laravel Mastery
Coaching Class Program

KritiMyantra

Transform from beginner to Laravel expert with our personalized Coaching Class starting June 16, 2025. Limited enrollment ensures focused attention.

Daily Sessions

1-hour personalized coaching

Real Projects

Build portfolio applications

Best Practices

Industry-standard techniques

Career Support

Interview prep & job guidance

Total Investment
$200
Duration
30 hours
1h/day

Enrollment Closes In

Days
Hours
Minutes
Seconds
Spots Available 5 of 10 remaining
Next cohort starts:
June 16, 2025

Join the Program

Complete your application to secure your spot

Application Submitted!

Thank you for your interest in our Laravel mentorship program. We'll contact you within 24 hours with next steps.

What happens next?

  • Confirmation email with program details
  • WhatsApp message from our team
  • Onboarding call to discuss your goals

Tags

Comments

No comments yet. Be the first to comment!

Please log in to post a comment:

Sign in with Google

Related Posts