The pattern must be obvious by now – in ABAC, access is defined by the attributes on the user or service, and a policy that enforces what actions these attributes are allowed to perform. As we saw in the above section, implementing RBAC is relatively simple but maintaining it over time becomes cumbersome as the system grows and permissions get more fine-grained. With ABAC, it's the opposite. Implementing it can be a herculean task but once complete, maintaining it is relatively simple and efficient.
With RBAC, every action that can be carried out in a system is tied to a complex set of role combinations. If a new role is introduced, every action that this new role can access must be updated. However with ABAC, you can create a central policy engine in which you define complex boolean logic for what attributes are allowed to do based on various conditions. ABAC is a great model for fine-grained (deep/specific) access control whereas RBAC is good for coarse-grained (broad/generic) access control.
It's also important to note that attributes can be about anything or anyone:
Let's revisit the Wookie Inc. example from the RBAC section. We created a simple RBAC management model for an IT admin As the organization grows and enters new markets, the access requirements also go up, introducing all sorts of complexity:
All of these requirements aren't uncommon for companies to address as they grow. Let's take a deeper look at the last one on the list: exposing APIs for public consumption. This can be third party developers that want to build against the platform or customers that need to build custom workflows. Either way, making sure the right user has the right privileges is incredibly important and difficult to implement. Unlike a product where actions are simple and what a user can do is based on roles, API actions are more granular.
This adds more complexity to API authorization Take a simple music playlist API, can the consumers of my API:
Even in the simplest of scenarios, authorization can get complex quickly.
All of these actions can be modelled as attributes of the resource that's being accessed. For example, being able to add, edit user details are attributes of the user resource. When writing code, I need a better way to model these attributes. We can utilize scopes here. If you recall, back in the Authentication chapter, OAuth 2.0 had the concept of scopes. We can use that model again here:
The naming convention can be anything you prefer. You could also model some of these as read_name, edit_name, etc.
We now have a model for all the resource types and the various actions that can be carried out on these resources. You can also take this a step further and define more granular attributes: playlists can be public or private. Songs can be explicit or non-explicit.
We can repeat the same model for users also. Users can:
These attributes can be defined on the user object however you like:
/users id Name admin yes or no subscription free, family, premium /preferences /profile /playlists
These are all user attributes and I can model the actions on them using scopes in a similar fashion:
At the same time, you can use these user attributes to enforce access:
Using this model, you can now architect a simple model for making authorization decisions. ABAC has a standardized architecture that we can use. Let's take an simple example: Leia is a free user that wants to edit Han's workout playlist. Editing playlists depends on a simple factor: It is only available to paid members.
How would this flow?
There are multiple ways to architect this but ABAC proposes the following architecture:
Using this, let's see how Leia's request to edit Han's playlist will be evaluated:
Leia presses the "Edit Playlist" Button → Request is routed to PEP → PEP constructs an authorization request → PEP requests edi:playlist, edit:description scopes along with some identifying information like user id → PDP uses this information to lookup policy, user info, and returns allow or deny.
While this is a simple example, from it we can extrapolate more complex requests and apply the same architecture for an entire system. For APIs, the PEP is usually the API Gateway. This gateway can then rely on an internal policy engine or potentially using information from a 3rd party identity provider to act as the PDP.
ABAC is a powerful and flexible approach for API authorization that requires an early investment but scales efficiently as your requirements and use cases As a general rule of thumb to decide if ABAC is better than RBAC, estimate how granular your authorization must be. Starting with RBAC for a limited set of roles and actions is a safe choice but as the number of roles and permissions increase, ABAC becomes a better choice. ABAC is also great at establishing governance policies and implementing legal/data protection compliance requirements.
The OAuth 2.0 framework is specifically designed for ABAC that works for many use cases, especially for APIs. When you combine it with tools like JWTs and OpenID Connect, you have a token which represents an authenticated user, additional context information such as their profile, and the scopes to which they have authorization. The OAuth 2.0 extensions allow you to implement RBAC + ABAC and scale as your API and use cases grow.