Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

SigalZ's avatar

Spatie permissions part via role part direct

Is it possible to have a user that has some permission of the role but not all of them?

For example: A user has the Admin role, the Admin role has permissions: A, B and C The user has the Admin role, but I want the user to have only A and B permissions.

Can this be done with Spatie Permissions?

0 likes
5 replies
fylzero's avatar

@sigalz Yes, this can be done. It is actually considered a best practice to use can to check for abilities, not roles. You can write your roles to contain cross-cutting abilities. For example an Author, Editor and Admin. An Admin can Edit, so can an Editor. So when you're checking if someone can edit, check if they can edit... don't just check their role.

Think of roles as a way to group abilities, but always check against actual abilities (not simply roles) when writing your code.

If I remember correctly, this video kind of lays out this practice at some point. https://www.youtube.com/watch?v=B2M3FCjRz6w&t=1392s

iosononando's avatar
Level 52

Well, the solution seems simple enough, accourding to their documentaion. But there's a catch: you need to re-think your strategy regarding roles and permissions because there is no way to revoke a permission granted through a role (because it makes little sense).

You should instead assign to roles ONLY the permissions that everybody in that role will have. If you want certain people with a role to have extra permissions, then you add them directly, or via a new role.

Given this world:

$adminRole = Role::create(['name' => 'Admin']);

// all the permissions in your system
$read = Permission::create(['name' => 'read']); // id 1
$create = Permission::create(['name' => 'create']); // id 2
$editOwn = Permission::create(['name' => 'edit own']); // id 3
$editFromOthers = Permission::create(['name' => 'edit from others']); // id 4
$deleteOwn = Permission::create(['name' => 'delete own']); // id 5
$deleteFromOthers = Permission::create(['name' => 'delete from others']); // id 6

This, as far as I can tell, is what you do and it doesn't work:

// all admins have all permissions
$permissions = Permissions::all();
$adminRole->syncPermissions($permissions);

// a user with a role should not have some admin permissions
$admin = User::first()->assignRole($adminRole);
$admin->revokePermissionTo('delete from others');

// this returns true because the permission is not directly given to the user, but it is inherited from the role
$admin->hasPermissionTo('delete from others'); // true :(

What I would suggest you to do, is something like:

// your standard admin role with permissions that are granted to everybody in the role
$adminPermissions = Permission::find([1, 2, 3, 5]); // deal with their own stuff
$adminRole->syncPermissions($adminPermissions);

// your standard admins 
$oneAdmin = User::find(1)->assignRole($adminRole);
$anotherAdmin = User::find(2)->assignRole($adminRole);
$trustWorthyAdmin = User::find(10)->assignRole($adminRole);

// now, this person is special
$trustWorthyAdmin->givePermissionTo('edit from others');
$trustWorthyAdmin->givePermissionTo('delete from others');

// when trust-worthy-admin becomes not so much trust-worthy
$trustWorthyAdmin->revokePermissionTo('delete from others');

// this returns false, which is what you want
$trustWorthyAdmin->hasPermissionTo('delete from others'); // flase :D

In alternative, when more people are involved:

// your standard admin role with permissions that are granted to everybody in the role
$adminPermissions = Permission::find([1, 2, 3, 5]); // deal with their own stuff
$adminRole->syncPermissions($adminPermissions);

// your new powerfull super admin role
$superAdminPermissions = Permission::find([4, 6]);
$superAdminRole = Role::create(['name' => 'Super Admin']);
$adminRole->syncPermissions($permissions);

// standard admins
$oneAdmin = User::find(1)->assignRole($adminRole);
$anotherAdmin = User::find(2)->assignRole($adminRole);

// trust-worthy admins
$trustWorthyAdmins = User::find([8, 9, 10])->assignRole($adminRole);
$trustWorthyAdmins->assignRole($superAdminRole);

You should also have in mind their suggestion on dealing with roles and permissions:

It is generally best to code your app around permissions only. That way you can always use the native Laravel @can and can() directives everywhere in your app.

Hope this helps!

jlrdw's avatar

RBAC and query scopes working together is one way to narrow down a query.

For example a situation where if admin all records are shown, but if regular user only the users records are shown.

So a query scope is where to fine tune these things.

Edit:

Permissions are assigned to roles.

  • admin can do certain things
  • bookkeeper can do certain things

So if Bob has only admin role and logs in he can do admin stuff.

Sally has both roles, logs in, can do both.

However when Bob is logged in, Bob cannot be fumbling and messing around with bookkeeping.

You have to remember, some folks will have duel roles.

Bob can however view general user data and edit if needed as an admin.

Keep it simple, just ask yourself this.

What can and cannot the logged in user do and not do.

Please or to participate in this conversation.