Permit
Plain-Elixir, DSL-less, extensible, agent-agnostic authorization library for Elixir.
Originally briefed and announced in Michal Buszkiewicz's CuriosumElixir Meetup #5 in 2022.
Checklist - outline of development goals
- Rule definition syntax
- Defining rules for Create, Read, Update and Delete actions
- Defining rules for arbitrarily named actions
- Authorization resolution
- Authorizing a subject to perform a specific action on a resource type (i.e. struct module, Ecto schema)
- Authorizing a subject to perform a specific action on a specific resource (i.e. struct, loaded Ecto record)
- Loading and authorizing a record based on a set of params (e.g. ID) and subject
- Building Ecto queries scoping accessible records based on subject and resource type
- Phoenix Framework integration
- Authorizing singular resource actions (e.g.
show,update)- Plug / Controller
- LiveView
- Preloading record (based on params) in singular resource actions and authorizing the specific record
- Plug/Controller
- LiveView
- Authorizing non-singular resource actions (e.g.
index)- Plug/Controller
- LiveView
- Preloading accessible records in non-singular resource actions (e.g.
index)- Plug/Controller
- LiveView
- Authorizing singular resource actions (e.g.
- Absinthe integration
- Figuring out mapping and/or extending the current permission definition paradigm to accomodate GraphQL usage
- Implementing a PoC
- Framework adapters
- Refactor resolver to provide a clear and straightforward way to develop library adapters
- Figure out what other frameworks we could adapt to using this library
- Documentation
- Examples of usage for each compatible framework and scenario
- Guide for developing library adapters
Agent-agnostic: what does it mean?
permit is implemented with extensibility in mind, and the purpose of this is to ensure that for all concerns of the app that require authorization a single permission definition base should be used as the source of truth.
For example, if you join the monorepo bandwagon, you should be able to nicely drop your authorization into whatever's driven by Plug (Phoenix controllers) as well as into Phoenix LiveView, and perhaps even more - because it's very likely that your codebase will use multiple frameworks to process data that requires authorization.
Hence, for want of a better word, I coined the agent-agnostic term to describe the mindset behind this - no matter if the agent is Plug, Phoenix LiveView, or in fact whatever else you might write an adapter for (you're invited!), you'll basically want to just do something like this (LiveView example):
use Permit.LiveViewAuthorization,
authorization_module: MyApp.Authorization,
resource_module: SomeEctoSchema
I should've explained what an agent is according to this definition. An agent is a source from which one may reason about:
- who is doing the action (the subject),
- what they are doing (the action - read, create, update, delete, or something custom-named),
- what is the action performed on (the object).
In Phoenix, for example, you usually have something like :current_user in your conn's assigns (the subject), a :show controller action easily maps to be a :read action, and the object can usually be taken from params[:id].
Likewise - in LiveView, you surely have a way to determine who the current user is. The action name can be taken from assigns[:live_action], and the object can also be found by ID. In this case, it's also important to be able to use handle_params to trigger authorization when appropriate.
You can imagine different frameworks coming into play like this. In these particular cases, Permit.LiveViewAuthorization and Permit.ControllerAuthorization determine the who and the what and talk to Permit.Resolver which, once the who and the what is known, determines whether the current permissions should allow the user to perform the action. And this is exactly what you should do to create any other adapter.
Installation
If available in Hex, the package can be installed
by adding permit to your list of dependencies in mix.exs:
def deps do
[
{:permit, "~> 0.1.0"}
]
end
Documentation can be generated with ExDoc and published on HexDocs. Once published, the docs can be found at https://hexdocs.pm/permit.