ExCedar

ExCedar is an Elixir library that wraps the Cedar authorization policy engine via a NIF built with Rustler. It gives Elixir applications a fast, idiomatic interface to Cedar — evaluating authorization decisions against policies and entity stores — without requiring users to install a Rust toolchain, thanks to precompiled NIF artifacts distributed with the package.

Installation

Add ex_cedar to your dependencies in mix.exs:

def deps do
[
{:ex_cedar, "~> 0.1"}
]
end

Usage

Authorize

policy = """
permit(
principal == User::"alice",
action == Action::"view",
resource == Document::"doc1"
);
"""
entities = [
%ExCedar.Entity{
uid: ExCedar.EntityUid.new("User", "alice"),
attributes: %{},
parents: []
}
]
request = %ExCedar.Request{
principal: ExCedar.EntityUid.new("User", "alice"),
action: ExCedar.EntityUid.new("Action", "view"),
resource: ExCedar.EntityUid.new("Document", "doc1"),
context: %{}
}
{:ok, %ExCedar.Decision{decision: :allow}} = ExCedar.authorize(policy, entities, request)

For multiple requests against the same policy set, compile once and reuse the handles:

{:ok, ps} = ExCedar.PolicySet.compile(policy)
{:ok, ents} = ExCedar.Entities.from_list(entities)
{:ok, %ExCedar.Decision{decision: :allow}} =
ExCedar.Authorizer.authorize(ps, ents, request)

Validate

Use ExCedar.Schema and ExCedar.Validator to check that your policies are consistent with your schema before deploying them:

schema_text = """
entity User;
entity Document;
action "view" appliesTo {
principal: [User],
resource: [Document],
context: {}
};
"""
{:ok, schema} = ExCedar.Schema.compile(schema_text)
{:ok, ps} = ExCedar.PolicySet.compile(policy)
{:ok, %ExCedar.ValidationResult{validated?: true, errors: [], warnings: _}} =
ExCedar.Validator.validate(ps, schema)

You can also pass a compiled schema to authorize to enable type-aware evaluation and request shape validation:

ExCedar.Authorizer.authorize(ps, ents, request, schema: schema)
# or via the one-shot facade:
ExCedar.authorize(policy, entities, request, schema: schema_text)

Policy templates

Cedar supports template policies with ?principal and ?resource slots. Use ExCedar.PolicySet.link_template/4 to bind slots and get a new, immutable handle.

Cedar assigns ids ("policy0", "policy1", ...) when parsing policy text, so discover the template id with template_ids/1 rather than hardcoding it:

template = "permit(principal == ?principal, action, resource);"
{:ok, ps} = ExCedar.PolicySet.compile(template)
[template_id] = ExCedar.PolicySet.template_ids(ps)
principal = ExCedar.EntityUid.new("User", "alice")
{:ok, ps2} = ExCedar.PolicySet.link_template(ps, template_id, "alice_policy", %{principal: principal})
# ps is unchanged; ps2 includes the linked policy
ExCedar.PolicySet.policy_ids(ps2)
# => ["alice_policy"]

Handles

ExCedar.PolicySet.compile/1, ExCedar.Schema.compile/1, and ExCedar.Entities.from_list/1 return opaque NIF resource handles (ResourceArc). These handles are:

Telemetry

ExCedar emits :telemetry span events around native operations. See ExCedar.Telemetry for the full event contract.

Events:

Precompiled NIFs

By default, ExCedar downloads a precompiled NIF for your platform at compile time — no Rust toolchain required. To force a source build (for example, when developing ExCedar itself or targeting an unsupported platform), set EX_CEDAR_BUILD=1 before compiling:

EX_CEDAR_BUILD=1 mix compile

Documentation is available at https://hexdocs.pm/ex_cedar.