type1fool
Arbiter - Role Based Authorization
Backstory
Before I became a full-time developer on a PHP team in 2018, I had been studying role based authorization (RBA) for an Elixir application I was developing part-time. Ever since, I have missed working in Elixir.
To sharpen my Elixir skills, I want to create an RBA library. There are a few existing libraries, but they seem to be intended for single-tenant applications. I think there is room for a multi-tenant library for B2B applications that serve multiple businesses.
Arbiter 
So far, I have written about the intent and preliminary design in the readme. I have also created the modules I expect to need, and started writing tests for the Organization module. I’m hoping to TDD this project to discover the optimal abstractions and to satisfy potential security requirements. ![]()
As I get started on the design, I want to hear from potential users to test my ideas. It’s worth noting is that this is my first open source project. I have been working on internal PHP applications and a custom framework, but nothing public-facing. I’ve learned the importance of hearing from users before spending hours/weeks on implementation.
Question Time
- Have you used one of the existing libraries or built custom RBA tools?
- What were the benefits and pain points?
- Do I need a Policy module?
- What are some possible hard requirements for adoption?
- Could the library accept (potentially decorate) a User struct from other auth libraries/modules?
- How?
- If Ecto is a dependency, should it default to ETS, SQLite, or Postgres?
- Could/should the library avoid persistence entirely, leaving that to the user?
- Would telemetry be useful in this kind of library?
- Do you have any other suggestions?
Most Liked Responses
thojanssens1
Personally I think what’s missing is the API you eventually want to provide for the library users.
I came to the conclusion that authentication and authorization is way too application-specific to make a library out of it. Authorization is actually vague as it can mean many different systems.
But change my mind ![]()
To elaborate this thought, take for example authentication and Pow. Pow requires you to inject code (use) in many layers of your application (controllers, views, routes, etc.) for it to work. Even though many devs like and use it, it makes more sense for me to use a scaffolding tool like phx.gen.auth that provides a codebase from which you can customize to your application needs. The fact that Pow must inject code application-wide is for me a clear sign that this should be application-specific code.
A lot of the topics and questions you raise concern business logic (user, team, organization, etc.) and I suspect the library might impose a minimum of conventions to follow in one’s business logic for it to work, but that is something I’ll never want to compromise. The library should work over the existing business logic without a change.
In my case, I work on calendars and a huge part of the authorization is sharing calendars between users with permissions. I have a CalendarSharingPermission Ecto schema that holds those permissions. Would I want to replace this calendar sharing table by a more general authorization solution? I think not, as it’s actually quite complex and specific, and I would also lose in terms of semantics and readability, and customization and flexibility.
I’m not sure what is the library’s goal (as I said, missing a demo API/usage), but you might consider the alternative of creating a blog post with your knowledge about authorization systems and provide sample code that someone can copy over and customize (similar to scaffolding).
al2o3cr
General advice: for the first pass at the idea, MAKE DECISIONS. Yes, eventually you might need to support primary keys of various types or totally different persistence - but trying to force everything to be too generic too early is a recipe for over-abstraction (see also… most of the last 30 years of OOP).
As @thojanssens1 mentioned, the hard part of RBAC is the interface the rest of the system uses: how does application code tell Arbiter what an “action” is? How will Arbiter answer questions like “show me the most recent 20 Widget records that this user can see”?
A good way to learn the answers to these questions (and have a nice demo to show people) is to build your abstractions inside a demo application and only then try to abstract them into a library.
On the organizations branch, it feels like the documentation is already suggesting a limitation of the interface. In this commit this example is added:
Clerks may start an order, add items, remove items, place an order on hold, accept payment method(s), and complete the order.
permissions: [
{:order, [:create, :update]},
],
Managers would likely include the same permissions as clerks, but would also be able to cancel orders, process refunds, and view reports.
permissions: [
{:order, [:create, :read, :update, :delete]},
{:report, [:read]},
],
The words used to describe the permissions (“clerks can place an order on hold”) are much more specific than the actions used to represent the permissions (order: [:create, :update]).
For instance, can a clerk update an order that’s already been shipped? Can a clerk EVER update the address on an order? “update” is very wide…
Some of this may be a matter of picking a better data model - for instance, only giving managers the “process refund” permission is tricky if it’s viewed as an “order update”, but easier if it’s a “refund create”.
harmon25
I have been considering using Bodyguard — Bodyguard v2.4.1 (hexdocs.pm) to handle relatively simple authorization requirements.
Elixir/Erlangs pattern matching capabilities lends itself quite well for this type of code, which is one of the reasons I like Bodyguard.
On the more complex end - think AWS/GCP policies. Take a look at Zanzibar: Google’s Consistent, Global Authorization System
And ORY Keto which is “the first and only open source implementation of Zanzibar”
Open Policy Agent is also worth looking into for inspiration. Maybe building on top of something like that would make sense. (OPA is what earlier versions of Keto were built on)








