Skip to main content

Black Friday 2025! Only until December 1st: coupon FRIDAY25 for 40% off Yearly/Lifetime membership!

Read more here
Tutorial Free

Laravel Users with Multiple Roles: Switching Between Roles

June 24, 2023
5 min read

Working with applications that have multiple roles can require you to have a Role Switcher to allow your user to act in a different role. For example, a user can be a doctor, but also a patient. In this practical example, we'll add role-switching to our navigation bar to allow this.


Setup

In our application, we have the following:

  • Users table
  • Roles table (provided by Laravel-permission) as PolyMorphic table model_has_roles
  • Pivot table for users and roles

Which will look like this in our database:


Step 1. Adding Current Role to Users Table

First, we need to add a current_role_id column to our users table to remember what role the user picked last:

Migration

Schema::table('users', function (Blueprint $table) {
$table->foreignId('current_role_id')->nullable()->constrained('roles')->after('email');
});

After adding it, we need to make it fillable in our User model and define a relationship:

app/Models/User.php

use Spatie\Permission\Models\Role;
 
// ...
 
protected $fillable = [
'name',
'email',
'password',
'current_role_id'
];
 
// ...
 
public function currentRole(): BelongsTo
{
return $this->belongsTo(Role::class, 'current_role_id');
}

Notice: You will have to update Factories, Tests, or Seeders to set a default role too.


Step 2. Role Switcher Controller and Route

Before working on the view, we must create a controller to handle the role switching. We'll call it SwitchRoleController:

app/Http/Controllers/SwitchRoleController.php

use Spatie\Permission\Models\Role;
 
// ...
 
class SwitchRoleController extends Controller
{
public function __invoke(Role $role)
{
abort_unless(auth()->user()->hasRole($role), 404);
 
auth()->user()->update(['current_role_id' => $role->id]);
 
return to_route('dashboard'); // Replace this with your own home route
}
}

Register it in your routes/web.php file:

routes/web.php

// ...
 
Route::middleware(['auth'])->group(function () {
// ...
Route::get('/switch-role/{role}', SwitchRoleController::class)->name('switch.role');
// ...
});
 
// ...

Step 3. Role Switcher in Blade Menu

Now we can focus on adding the Switcher to our navigation bar.

We update the default Laravel Breeze top-right navigation menu, adding two sub-items:

  1. Information about the current role
  2. If user has multiple roles, showing all of them with the link to switch role

resources/views/layouts/navigation.blade.php

{{-- ... --}}
 
<!-- Settings Dropdown -->
<div class="hidden sm:flex sm:items-center sm:ml-6">
<x-dropdown align="right" width="48">
{{-- ... --}}
 
<x-slot name="content">
<x-dropdown-link href="#">
{{ __('Logged in as: :role', ['role' => auth()->user()->currentRole->name]) }}
</x-dropdown-link>
 
@if(auth()->user()->roles->count() > 1)
@foreach(auth()->user()->roles->where('id', '!=', auth()->user()->current_role_id) as $role)
<x-dropdown-link :href="route('switch.role', $role->id)">
{{ __('Switch to :name', ['name' => $role->name]) }}
</x-dropdown-link>
@endforeach
@endif
 
<hr/>
 
{{-- ... --}}
</x-slot>
</x-dropdown>
</div>
 
{{-- ... --}}

Loading our page will now show us the current role and a list of other roles we can switch to:

This is it! Users can now switch between active roles within your system and return to the same role when logging in. You can add more functionality to your application based on this role.


Bonus: Role-Based Menu Example

Want to show different menu based on the current role? Here's one possible approach:

resources/views/layouts/navigation.blade.php

{{-- ... --}}
 
<!-- Navigation Links -->
<div class="hidden space-x-8 sm:-my-px sm:ml-10 sm:flex">
@includeIf('layouts.menu.' . auth()->user()->currentRole->name)
</div>
 
{{-- ... --}}

So, we're including the Blade file with the role name in it. We're using the includeIf() method which would also check if that file exists.

And we can create the partials for each role:

resources/views/layouts/menu/doctor.blade.php

<x-nav-link :href="route('dashboard')" :active="request()->routeIs('dashboard')">
{{ __('Dashboard') }}
</x-nav-link>
<x-nav-link href="#">
{{ __('My patients') }}
</x-nav-link>
<x-nav-link href="#">
{{ __('My calendar') }}
</x-nav-link>
<x-nav-link href="#">
{{ __('My profile') }}
</x-nav-link>

resources/views/layouts/menu/patient.blade.php

<x-nav-link :href="route('dashboard')" :active="request()->routeIs('dashboard')">
{{ __('Dashboard') }}
</x-nav-link>
<x-nav-link href="#">
{{ __('My appointments') }}
</x-nav-link>
<x-nav-link href="#">
{{ __('My health') }}
</x-nav-link>
<x-nav-link href="#">
{{ __('My profile') }}
</x-nav-link>

After this, loading our page will show us the correct navigation links based on the current role:

Doctor

Patient

Enjoyed This Tutorial?

Get access to all premium tutorials, video and text courses, and exclusive Laravel resources. Join our community of 10,000+ developers.

Comments & Discussion

D
Diovane ✓ Link copied!

What database design tool did you use?

M
Modestas ✓ Link copied!

This was an existing database view from DataGrip (jetbrains darabase tool)

MD
Muhammad Dikky Purwanto ✓ Link copied!

i want to this project , but iam dont have money

DS
D.H SIMON ✓ Link copied!

Is this feature possible without using spatie/laravel-permission?

M
Modestas ✓ Link copied!

Yes it is. But you will have to build everything yourself :)