Granular permissions with Laravel APIs & React frontend

Munaf Aqeel Mahdi
7 min readNov 21, 2021

--

In this article, I’ll explain how to implement the granular permissions system using Laravel APIs as our backend and React.js as our frontend (separated app) ..

Since we have our frontend separated from our backend connecting through the APIs, we won’t use Laravel blade views as the common way.

Introduction

In many web applications, we have a roles & permissions system .. that each user has a role, and each role has its own permissions, then each permission is used to authorize a specific feature in our app, as explained in the picture below:

Picture source: sukanyasen.medium.com

Ok, but!! .. what is granular permissions 🤔?

Generally, granular permissions refers to privileges granted by a system to you that allow you to construct site-specific roles based on certain requirements. — source

With granular permission you can have different content in the same view from one user to another according to their permissions granted.

For example,

We have an application with two users:

The picture above explains the whole idea of the Granular Permissions

As you can see in the picture above,

— The user with admin role has full access (all permissions) .. so he can access, create, update, delete, or comment on a post as well as users and other sections.

— The user with editor role has limited access (limited permissions) .. he can only access the posts view and edit them.

So, the idea behind the granular permissions is that we have control over our views according to system’s permissions set, and show/hide a specific feature in the view according to user’s permissions granted.

The Backend

We are going to work on an existing Laravel app (a backend API) I created, with authentication implemented by using Laravel Sanctum.

This api (Laravel App) contains only two models:

User model.

Post model.

with their Controllers, Resources, migrations, seeders, and routes all are ready.

Nothing too complicated! only an backend APIs to get, create, update and delete posts with users and authentication with API tokens.

The source code will be included at the end of this article on Github.

Now, let’s write some code!

Ok, now its time to move our hands 🖐 and write some code🤓

In Laravel, it is very easy to implement such a system with the help of @spatie/laravel-permissions package, it help us to easily manage user roles and permissions in a very simple way ..

let us first install laravel-permissions package in our app (you can follow the official docs):

composer require spatie/laravel-permission

then we have to publish the (config, migrations):

php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider"

then run the migrations:

php artisan migrate

Now we need to create all the permissions required by our app as our needs, then create a roles and give them a permissions .. then assign the roles to specific users,

Let’s create a seeder file to do that, run the following command:

php artisan make:seeder PermissionsSeeder

a seeder class will be created at database/seeders/PermissionsSeeder.php , open it and inside the run method we write our seeding code..

you can follow the code below:

It’s all described

Explaining the seeder class above:

  • First, reset cached roles and permissions if needed.
  • create an array of all our needed permissions in our app, then store them in the database.
  • create 2 roles (admin with full permissions, editor with only two or limited permissions).
  • Last thing, assign a role to a user .. user 1 as admin and user 2 as editor.

Then, we need to call the PermissionsSeeder.php class inside the run method of database/seeders/DatabaseSeeder.php as the following:

public function run(){     $this->call([          UserSeeder::class,
...
PermissionsSeeder::class, ]);}

Don’t put the UserSeeder (if exists/you have) after the PermissionsSeeder, because remember the users assigned at PermissionsSeeder (1 & 2)

Then run the seeding command:

php artisan db:seed

Now we have our users with their roles & permissions set 🤓 🎉

  • User 1 as admin with all permissions
  • User 2 as editor with 2 permissions only.

Two more steps left, to finish the backend side!

  • Step 1 — Authorize user actions against a given resource with our app APIs (because we NEVER TRUST CLIENT).
  • Step 2 — Return user’s permissions when authenticated, to use them later in our frontend.

Step 1

With Laravel you can authorize user actions against a given resource with two primary ways (using Gates, Policies) .. check out the official docs.

It’s up to you and your case, in my case I’ll authorize user actions using Policies via User Model

Example:

In my PostController.php, User have to be authenticated (Logged in) and authorized (has permission to access posts)

and so on for other controller’s methods to be authorized.

Step 2

I have a GET endpoint which is (/auth/profile) to get the authenticated user’s data by the access token sent along with the request, then it respond with user’s data .. that’s fine, but I need to get user role and permissions with the user’s data returned.

I’m using Laravel resources to transform the response data, so I have created a resource for Users called UserResource.php .. then in my AuthController.php @ profile method, I have returned the authenticated user’s data using this resource as showing below:

return response()->json([      ‘user’ => new UserResource(auth()->user())], 200);

My current UserResponse.php

As I said before, I need to add the user’s role and user’s permissions because we gonna need them at the frontend side.

so, it would be as the following:

Thats it for the backend side.🤓 ✅

The Frontend

First, let me explain the common way to use permissions in our views to show/hide a specific feature according to user’s permissions granted

The common way is by using Laravel Blade Views .. it is very easy with Blade directives (can, cannot, role, hasrole … etc)

Example:

But in our case, we are using React.js as a separated app from Laravel, connecting through the APIs .. so we don’t have Blade directives for authorization!

That’s why in the Backend section (STEP 2) we returned all the permissions of the authenticated user and his role.

Let me explain

In my React app, when a user login using the (/auth/sign-in) API endpoint, I store the login token using the Cookies, not storing user’s data .. so I need on page load to get the logged in user’s data then store it in the state management (Redux, Context API, …etc).

So, how to get the logged in user’s data?

Using the API endpoint (/auth/profile) .

By sending a GET request to (/auth/profile) with the token we stored in the cookies, we get a response like:

we store user’s data in our state management (in my case Context API) so we can then access user’s data anywhere in our app.

Last step, we can implement our own (can, cannot, hasrole … etc) methods so we can use them to authorize a specific feature according to users permissions same way as Laravel blade directives.

Example of implementing (can) method:

Put this method in the same place where you get user’s data (in my case at the Auth context of my state management) because it requires user’s data (permissions) to check on.

then we just have to import the (can) method anywhere in our app and use it as the following:

That’s it, we are all done!

You can implement the same approach with Vue.js/Angular.js/Svelte.js ..etc, its not just for React.js .. this was just an example of how to do it using APIs with separated frontend app from Laravel.

Advanced

After that, you can build a dashboard to control and (create/update/delete) roles and their permissions and assign a role to a user easily .. something like this:

Updating a role in a dashboard

by creating an endpoint to get role’s permissions grouped by section (products, posts …), then on update sync the permissions to the role using

$role->syncPermissions($request->permissions);

and so on.

That’s it for today, thank you for your time and see you in the next articles 👋❤️

Don’t forget to check out my Github account, and follow me on Twitter 😁❤️

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

Written by Munaf Aqeel Mahdi

Senior Software Engineer / UI UX Designer

Responses (4)

Write a response