Ash adapter for Parc, the framework-agnostic PARC authorization contract. AshParc binds Ash's policy DSL to one Parc policy, so a single declared policy authorizes every action across every resource.

Enforcement points

AshParc names one policy at two points in a resource's policies block:

Both points project the action's arguments and instance attributes into the request through the :arguments and :attributes options; :context lifts a chosen argument or attribute into request.context under a normalized key the preparers and decider read.

Usage

Declare the policy as a Parc.Pipeline (see parc) with AshParc.ResetAshContext as its first preparer, then gate a write from the resource's policies block:

policy action(:update) do
  authorize_if AshParc.can_perform(MyApp.AuthzPolicy, attributes: [:organization_id])
end

Row-scope a read with a resource-owned Ash.Policy.FilterCheck that runs the policy and turns the verdict into a filter, and name it the same way:

policy action(:read) do
  authorize_if MyApp.Widget.ReadScope
end

That check builds its request with AshParc.build_request/3, and the read scoping needs

config :ash, policies: [no_filter_static_forbidden_reads?: false]

so a {:deny, _} scopes the read to no rows instead of raising Ash.Error.Forbidden.

Installation

Add ash_parc to your dependencies in mix.exs:

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

The API reference is at hexdocs.pm/ash_parc.