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

scott80109's avatar

Best practices for ACL/Authorization

I'm building a large scale app that will have dozens (perhaps hundreds) of separate permissions. I'm looking at Spatie's Laravel-Permission package for ACL, but struggling to figure out exactly how to use it. The business owner wants to be able to fine tune what actions his employees can perform in the website.

Example Use Cases:

  • Admin 1 is able to "impersonate users", "view sales history", "create users", and "delete users"
  • Admin 2 is able to "view sales history", and "create users"
  • Admin 3 is able to "view sales history"

This is an obviously oversimplified example that could be accomplished with 3 separate roles. However, there are dozens of users, and there will be many, many permissions. The potential permissions combinations will be so large that trying to define all of the scenarios into separate roles would be impossible/impractical.

For those who have dealt with this problem, what solution did you go with? I'm open to other packages, or none at all if it's easier to implement with pure gates and policies.

My current thoughts are instead of assigning permissions to roles, assign them to users directly via Spatie's Direct Permissions feature, and testing by hasDirectPermission() instead of testing by roles.

In theory it sounds good, but I'm not sure how it will work out in practice. Thoughts?

0 likes
14 replies
tykus's avatar

You can use role(s) for this. A user can have an ability through either role permissions or direct permissions. The Authorization Gate is not concerned how a User has the ability; only that it has the ability. So you can give the role appropriate permissions; and supplement individual users with direct permissions.

scott80109's avatar

@tykus What if the "Admin" role has all permissions listed above for Admin1? Assigning the "Admin" role to Admin2 and Admin3 gives them all of those permissions. From my understanding, you can't revoke permissions given to a user that belong to the role you assign them.

tykus's avatar

@scott80109 then Admin2 and Admin3 do not have Admin role 🤷‍♂️. You should make roles with the appropriate permissions; then supplement individual user's permissions directly.

1 like
Snapey's avatar

i would group permissions into roles aligned with business areas and give users potentially multiple roles

so for instance one user might be in charge of the sales team, so they get manager role (of people), sales admin role, order capture role and sales reports role whereas someone else in his team might only have sales admin role

when you assign permission s to a role and then multiple roles per user, the user gets a superset of permissions from all roles.

In your code always test permissions not roles. Apart from the place where you apply roles to users, you should not see mention of roles any where in your code

Don't forget you might need scoped roles, ie you can manage people but only in your own team

1 like
scott80109's avatar

@Snapey That still wouldn't work because it wouldn't provide the fine tuning capability needed. The business owner may not want a person who is assigned the manager role to have every one of those permissions. What if managers can hire and fire people, but the owner wants one particular manager to only have the ability to hire people?

There are just too many possibilities here. The current app is a ZF1 app that I'm rebuilding with Laravel. The way it works now is that on the user management page, there are checkboxes for actions he wants to allow/disallow. It's a little easier with the Zend ACL than what I've seen so far in Laravel, but it is kind of limited because there's only a subset of permissions that he wants in the refactored app.

scott80109's avatar

@Snapey Nice! That UI is exactly what I'm looking for. Cloning your repo to take a look at the code now. Thank you for that!

scott80109's avatar

@Snapey Confirmed. This is just what I needed. Thanks again for the great example.

Snapey's avatar

@scott80109 Just a tip. Something I have learned since doing this one. Name your permissions without using a dot. In another project, I was trying to refer to a policy using the authorize method

$this->authorize('election.create', $election);

does not work, because in the policy I needed

public function election.create($election)

which is not possible to have as a function name. So in this project the permissions are like election_create

1 like
jlrdw's avatar

If you view the free laravel 6 from scratch and laravel 8 from scratch series, Jeffrey demonstrates authentication and authorization, that would be the best practice.

Furthermore the code is available on GitHub to learn from and study.

And don't let yourself be concerned about a role. Whether someone owns a company or is the janitor, just remember that logged-in user either can or cannot do something with their role/s.

nhil777's avatar

Can't you with spatie/laravel-permission assign permissions without roles?

Example:

$user->givePermissionTo('edit articles');
$user->givePermissionTo('update articles');

And then check if user has the permission to perform a specific action

$user->can('edit articles');

Or with Blade:

@can('edit articles')
...
@endcan
scott80109's avatar

@nhil777 Yes, this is what I was thinking when I described just assigning permissions to users instead of roles.

scott80109's avatar

@nhil777 I'm still in the planning phase right now. Was just looking for opinions and advice from others who has faced a similar issue.

1 like

Please or to participate in this conversation.