Hello, everyone!
I’m thrilled to introduce Zephyr, an open-source authorization library for Elixir that leverages the power of Relationship-based Access Control (ReBAC). Zephyr is inspired by Google’s Zanzibar and closely follows the syntax of Authzed’s SpiceDB.
How does it work?
The concept of ReBAC circles around the subject and its relation to an object. For example,
User Alice is the creator of Issue Typo. In this statement, User Alice is the subject, Issue Typo is the object, and the relation of Alice to Typo is “creator”.
We can save this relation via:
Zephyr.write!({"users", "Alice", nil}, {"issues", "Typo", "creator"})
We name user Alice and issue Typo for the sake of discussion only, but in the real world they should be unique identifiers like integer or uuid
With that said, we can define their relationship as something like:
definition :users
definition :issues do
relation(:creator, :users)
end
By extending the definition above, we can also say that creators can also close the issue:
definition :users
definition :issues do
relation(:creator, :users)
relation(:closer, :creator)
end
With this, we can then check that Alice is a creator and also a closer
iex> Zephyr.check(issue, "creator", alice)
true
iex> Zephyr.check(issue, "closer", alice)
true
The issue and alice here are ecto schema with id and table metadata.
We can also relate an object to another object. For example, a statement saying Maintainers of Repository Zed that is a parent of Issue Typo can also close the issue:
definition :users
definition :repositories do
relation(:maintainer, :users)
end
definition :issues do
relation(:creator, :users)
relation(:parent_repository, :repositories)
relation(:closer, :creator + (:parent_repository > :maintainer))
end
Let’s try to save a maintainer relation to a parent repository and also a parent repository relation to the issue, respectively:
Zephyr.write!({"users", "Bob", nil}, {"repositories", "Zed", "maintainer"})
Zephyr.write!({"repositories", "Zed", nil}, {"issues", "Typo", "parent_repository"})
Now we can check that Bob can also close Issue Typo:
iex> Zephyr.check(issue, "closer", bob)
true
Key Features:
- ReBAC Authorization: Zephyr allows you to define and enforce complex access control policies based on the relationships between users and objects in your application.
- Inspired by Zanzibar and SpiceDB: While rooted in the concepts of Google’s Zanzibar, Zephyr closely follows the semantics of SpiceDB, making it familiar to those who have used these systems.
- Powerful Operators: Zephyr supports union, exclusion, intersection, and walk operators for creating nuanced access control policies.
Caveat (Important!!)
This library is still in its alpha version there is still more work to do like the extend API in addition to write
and check
, more fixes, and of course documentation.
Feedback and Contributions:
I’d love to hear your thoughts on Zephyr. Contributions, whether they be bug reports, feature requests, or code, are always welcome. Let’s work together to make Zephyr a powerful tool for the Elixir community!