Dead simple permissions for Laravel
Permissions can be complex. Here’s an easy solution.
tl;dr: If you’re not interested in setting this up yourself and would rather just install a package, I wrote one called Deadbolt. Check it out on GitHub.
I’ve built a number of Laravel applications over the years and most of them had some sort of authorisation requirement. Some users should have access to certain resources, while other users should not. It’s easy, right? Add a boolean column to your users table that gives users access to that resource if it’s set to true. Done!
Sure, that works. But it’s really not very flexible. What happens when you have lots of resources? What if you need to protect other parts of your application? That simple boolean “flag” is quickly going to show its shortcomings. This is where you quickly start to realise that you need some form of permissions system. Luckily there are quite a few really awesome solutions to choose from, but by far the most popular (for good reason) is the laravel-permission package from the guys at Spatie. It has everything you could possibly want out of a permissions package for Laravel. If you’re looking for a really flexible, feature-rich permissions package, then that is definitely the right way to go. But every now and again, you just don’t need all of that. Sometimes, all you really want sits somewhere between the boolean flags and the power of Spatie’s solution.
I think that the approach I describe here fills that gap. It’s simple and is especially useful when you’re dealing with an SPA frontend (or my favourite at the moment: IntertiaJS). The idea is that you store assigned permissions directly in your users table as a JSON encoded string which is then available every single time you reference the
User model. No need for additional database tables.
I’ve also never really felt comfortable storing application permissions in a database table. Roles, sure, but permissions are often tied to the actions they authorize. Those actions generally are not described in a database table, so why do we do so with the permissions that authorise them?
Okay, let’s get on with it, then.
Update the user table migration
First, we need a place to store the permissions we’re going to give our users. I’ve already said that we’ll store assigned permissions right in the users database table. So update your users database table migration to include a
We’ll need to update our
User model to cast that column as a JSON object. Add the following protected property to
Now when we use
$user->permissions, we’ll get a PHP array of the permissions assigned to that user. That’s already better than the series of boolean flags I mentioned earlier.
Just remember that string columns usually have a fixed length. If you have lots of permissions, you might need something a bit longer.
Define the available permissions
You can define a new config file for this, but it’s perfectly fine to add things to the config files that are already included with Laravel. That’s kinda what they’re there for, anyway.
Add a new array to the end of the
auth.php file in your
config directory. We’ll use this to list the actual permissions we can potentially give to users.
The useful part of this is that we can now get a list of available permissions using the
config helper method:
$permissions = config('auth.permissions');
We can already start assigning permissions to our users when updating or creating them:
Using Laravel policies
I strongly recommend that you use policy classes to authorise actions on resources. As an example, let’s say we have an
Article model that represents blog articles in our database. Our users should have separate permissions to create, edit or delete articles. We can create a new policy for articles using a simple Artisan console command:
php ./artisan make:policy ArticlePolicy
This will create a new
/app/Policies/ArticlePolicy.php file. We can create methods in there that represent the actions we want to authorise. Write
delete methods that return a boolean. We’ll simply check if the required permission is in the array of permissions we can get from the
User model passed into the method.
Now that our policy is complete, Laravel provides a simple
authorize method that you can use from within your controllers that will let you authorize users using the policy class we created. So for example, in our
create method on our
ArticleController class, we can do this:
As a user, if you now try to make a request for the
/articles/create URI and the
articles.create permission doesn’t exist in your
permission array, you’ll get a 401 Unauthorized error.
That’s pretty simple, and easy to set up. It’s not all that easy to use right now. Especially if you’re going to need to check more than one permission.
Create a service class
Let’s create a simple service class that we can reach for when we need to manage a users permissions. That way we don’t need to mess around with the user model directly and we can add some useful additional features along the way. Create a new file called
Services/PermissionService.php. We’ll write a few simple methods to help manage the permissions for our users. Let’s start with something simple:
Right now, all this class can do is return an array of the permissions we put into the
auth.php config file. That’s not exactly exciting, or particularly useful. So let’s add a method that we can use to give our users new permissions.
We don’t want to add permissions that don’t actually exist, so we’ll first check that a permission is in the array we added to the
auth config. Only permissions that are in that array will then be added to the user. Let’s write a
give method that takes a
User instance and an array of permissions which we can call when we’re ready to assign permissions.
This method returns the service class itself so we can chain methods together if we want. Also, it might be better to rather fail here if a permission doesn’t exist instead of simply ignoring it. That way, you’ll be able to catch potential typo’s you might have missed.
We can also add a
super method which will automatically give the user ALL the available permissions in one go. The
super method just calls the
give method and passes in all the available permissions:
Okay, great! We can give users permissions. But what if we want to take permissions away? Let’s write a
revoke method and a
clear method to do just that:
Create a facade
I’m not going to explain facades here. You can read up about how facades work in the Laravel documentation. Just know that a facade is a really easy way to create a new instance of a class and get access to the methods on that class through a nice, easy-to-read interface.
You could easily use this service class without the facade if you don’t want to write a facade, but it does makes it a little sexier. So create a new class in
The facade will simply tell Laravel how to find the service class we already created. We do this by using a “key” that we’ll bind into the Laravel container. The facades
getFacadeAccessor method should return that key.
Once you’ve got your facade all sorted out, we need to register it. This is commonly done in the
AppServiceProvider in your
Providers directory. Update the
register method with the following:
That’s all we need to do to get the facade registered. Now we can use our new facade like this:
How about testing permissions though? At the moment, our
ArticlePolicy class is checking if a user as a permission by checking if that permission exists within the array stored in the
permissions column. There’s nothing really wrong with that, but we can do better. So let’s add a method to the
PermissionService that we can use to test if a user has a specific permission. We’re just moving the
in_array logic from the policy into our service class.
Now let’s update the
ArticlePolicy class so that it uses the
Permissions::has() method we just created:
That’s it. If we need to add permissions to our system, we just update the permissions array in the
auth.php config. We can add policies as we need and use the facade to give and revoke permissions. There’s a lot of room for improvement here, but the idea was to create something simple that is a little more flexible than adding an
admin boolean column.
I like using InteriaJS at the moment, so if I return the user to an Inertia page from a controller method like this:
return Inertia::render('Pages/Articles/Create', [
'user' => Auth::user(),
… in my Vue template I can easily do something like this:
No need to make extra HTTP requests to the application just to check if a user has permission to complete a task. I have the user object, so I have their permissions as well. If I share the authenticated user with all my Inertia views then I have those permissions everywhere, which is really handy.
Waring! Blatant self-promotion ahead…
I’ve used this approach a few times now, and even in one fairly large project and it works like a charm. Anyway, to make my life easier, I created a package for Laravel called Deadbolt and it’s similar to what I’ve described here, but with perhaps a little more grace and elegance, if I say so myself. The package has a bunch more features than this article and is probably a lot less error prone, but the basic idea is the same.
The package is MIT licensed, so use how you want. It’s still fairly new, but I’m using it a bunch at the moment, so it currently gets fairly regular updates.