AuvalOffice

This is a library to define an authorization policy. It is modeled after the authorize package, but I made my own for a simple reason:

Compared to authorize, this library has a couple of additional features:

Installation

At the moment, this library is not available on Hex, so install it via a direct github reference:

def deps do
  [
    # ...
    {:auval_office, github: "braunse/auval_office"}
  ]

HOWTO

Authorization happens in a policy module, which contains all the rules for a specific policy, and the associated fetchers:

defmodule Example.Policy
  use AuvalOffice.Policy

  # To define a policy, list rules one after another.
  # Basic rule syntax is like this:
  rule :a_symbol_or_string_naming_the_rule, action, subject, object do
    # Allow the access, and stop evaluating further rules
    :ok

    # As above, but provide additional decision context (e.g. for building an audit trail)
    {:ok, pigs: :learned_to_fly}

    # Disallow the access, and stop evaluating further rules
    :error

    # As above, but provide additional decision context (e.g. for building an audit trail)
    {:error, moon: :was_not_in_the_seventh_house}

    # Make no decision, and evaluate further rules
    :next
  end

  # Subject and object can be patterns, and bound names are available in the body of the rule
  rule :author_can_edit_blog_post, :edit, %User{id: id}, %Post{author_id: author_id} do
    if author_id == id do
      :ok
    else
      :next
    end
  end

  # Rules can be guarded by a condition.
  # The rule will be skipped unless the condition is true
  rule :author_can_edit_blog_post_shorter_definition, :edit %User{id: id}, %Post{author_id: author_id},
    when: id == author_id,
    do: :ok

  # Rules can refer to context by pattern matching, for example when additional information
  # has to be fetched in the course of evaluation
  rule :author_can_delete_blog_post_while_it_has_no_comments, :delete, %User{id: id}, %Post{author_id},
    context: %{post_comments: 0} do
    if author_id == id, do: :ok, else: :next
  end

  # To fetch the number of blog posts, use a fetcher.
  # You can match on subject, object, action and context.
  # As with rules, a guard clause can be given; the fetcher is skipped when the guard clause evaluates to false
  # Basic syntax:
  fetch :fetcher_id, :field_name, [parameter: pattern] do
    {:ok, value}
    # or {:error, error} to fail evaluation
  end
  
  # For example to fetch the number of blog post comments:
  fetch :blog_post_comment_count, :post_comments, object: %Post{id: id} do
    {:ok, BlogPost.count_comments()}
  end
end