Laravel SDK - Where Laravel Authorizations Left-Off
Introduction
The authorizations are decision mechanisms enforced in the most actions a user takes in an application. There is an enforced authorization decision for most of the components in your application.
In other words, this means spreading authorization logic all over the code, and creating a spaghetti code.
Laravel provides an organized way to manage such authorization checks. It offers two ways to authorize actions: gates and policies.
Gates are closures that determine if a user is authorized to perform a given action. Policies are classes that organize authorization logic around a particular model, or resource.
For more you can check this documentation.
Although Laravel seems to have created an organized solution for authorization, I will try to explain the cases where it fell short;
- Application Consistency
- Testing & Validate
- Scaling & Performance
Application Consistency
The Authorizations should be consistent through every layer of our application. Let’s demonstrate this consistency with an example. Assume we have build an blog application with following tech stack;
-Laravel for API
- VueJS for Frontend
And we’ll launch a new comments feature soon.
We should enforce an access check, in order to control who can comment. This can be done by comparing the relationship between resource, and user attributes.
Here are some examples;
A: Your user must meet one of the three options to be able to comment. These options are;
- If the user follows the owner of the post
- If the user is the owner of the post
- If the user is editor
B: Your user must meet one of three options to react to comments. These options are;
- If your user is a follower of the owner of the post
- If the user is the owner of the post
- If the user is editor
C: Your user must meet one of three options to reach comment settings. These options are;
- If the user is the owner of the post
- If the user is editor
You want to show users what’s relevant to their authority.
A: If the user is unauthorized for A, you do not want them to see the “Submit Comment” component.
B: If the user is unauthorized for B, You do not want the "give reaction" button to appear.
C: If the user is unauthorized for C, You do not want them to access "settings" button.
To satisfy these requests, you have created policies with Laravel controllers, and query database to enforce access check.
While this causes unnecessary database queries, this is even not the core problem.
Since your authorization logic is rooted in the backend code, your frontend can’t enforce access check when the page is rendered.
This will be annoying. Because your application will learn about authorization decision when the decision request has been made which is right after the job is done.
This means you have to push warnings such as “You’re not authorized to comment on this post”, which messes up the user experience in the first place.
Or worse, leave the user in the dark unintentionally. And they will think something is broken.
But why did they see the “comment” button if they’re not authorized to take action.
Even if you want to fix this, you will have to spend a lot of time to understand that your user meets the same conditions on both the front-end and the back-end. This means 2x more work for every change, and update.
And assume that you’ll launch on new platforms such as mobile, your engineering effort tops 3 times.
In other words, if you don't have a central authorization system your tests will be difficult, and interfaces for the parts of your application will be inconsistent.
Unfortunately, this will give different results for the same input and your users will see components that they are not authorized.
Permify removes the authorization logic from the application and behaves consistently wherever it is called. As a single point of access control for authorization logic.
It’s an authorization service facilitates consistent maintenance, modification, and testing of authorization logic across all consuming services or applications.
Testing & Validate
Your authorization logic is still dependent on your core product whether you choose adding a library or building it from starch.
And you have no assurance that your inputs will not be affected by changes in the application state when you run the application. This makes it harder to test and validate the authorizations enforced.
Permify is a service, by its nature stateless and independent which is decoupled from the application. This means it can be tested and verified on its own, regardless of application state.
With an isolated service, it's easier to reason about the authorization logic. We clearly know what our inputs are, and nothing changes them, thus we can also know what the expected results will be!
Scaling & Performance
An authorization solution should be able to make decisions based on the identity, attributes, and relationships between a user/resource.
Some of the information required to make an authorization decision is the data in your own database, and the solutions you use (laravel policies, gates, external libraries).
And you need to be able to decode this information in order to make a decision.
The solutions you use in the application queries the database to get authorization data, and make a decision as a result. Therefore, the performance of your authorization solutions is directly dependent on the application.
In the example of the blog comments we provided above, it wastes performance by making the decision to authorize more resources than the endpoint's own process just for commenting feature. To increase the performance of your application, you need to scale vertically.
On the other hand; Permify saves its own resources, and makes authorization decisions without affecting the performance of the application. Decisions are made faster because it pre-caches authorization data.
Since the authorization service is isolated from the application, it can be scaled horizontally as needed!