Ash.Authorizer behaviour (ash v3.27.3)

Copy Markdown View Source

The interface for an ash authorizer

These will typically be implemented by an extension, but a custom one can be implemented by defining an extension that also adopts this behaviour.

Then you can extend a resource with authorizers: [YourAuthorizer]

Summary

Functions

Apply field-level authorization to records that are already in memory, scrubbing any fields the actor isn't allowed to see.

Types

context()

@type context() :: map()

state()

@type state() :: map()

Callbacks

add_calculations(arg1, state, context)

(optional)
@callback add_calculations(Ash.Query.t() | Ash.Changeset.t(), state(), context()) ::
  {:ok, Ash.Query.t() | Ash.Changeset.t(), state()} | {:error, Ash.Error.t()}

alter_filter(filter, state, context)

(optional)
@callback alter_filter(filter :: Ash.Filter.t(), state(), context()) ::
  {:ok, Ash.Filter.t()} | {:error, Ash.Error.t()}

alter_results(state, list, context)

(optional)
@callback alter_results(state(), [Ash.Resource.Record.t()], context()) ::
  {:ok, [Ash.Resource.Record.t()]} | {:error, Ash.Error.t()}

apply_field_level_auth(resource, records, opts)

(optional)
@callback apply_field_level_auth(
  resource :: Ash.Resource.t(),
  records :: [Ash.Resource.Record.t()],
  opts :: Keyword.t()
) :: {:ok, [Ash.Resource.Record.t()]} | {:error, Ash.Error.t()}

Apply field-level authorization to a list of records that already have values populated in memory, without re-fetching them through a read.

Implementations should walk each record and substitute %Ash.ForbiddenField{} for any field the actor isn't allowed to see (typically via field policies).

This is the lightweight counterpart to add_calculations/3 + the read pipeline's field-policy scrubbing — used when you have records in hand and just need to enforce field-level visibility without running a load.

check(state, context)

@callback check(state(), context()) ::
  :authorized
  | {:data, [Ash.Resource.Record.t()]}
  | {:error, :forbidden, state()}
  | {:error, Ash.Error.t()}

check_context(state)

@callback check_context(state()) :: [atom()]

exception(atom, state)

(optional)
@callback exception(atom(), state()) :: Exception.t()

initial_state(t, t, action, t)

strict_check(state, context)

@callback strict_check(state(), context()) ::
  {:authorized, state()}
  | {:continue, state()}
  | {:filter, Keyword.t()}
  | {:filter, Keyword.t(), state()}
  | {:filter_and_continue, Keyword.t(), state()}
  | {:error, term()}

strict_check_context(state)

@callback strict_check_context(state()) :: [atom()]

Functions

apply_field_level_auth(resource, records, opts \\ [])

@spec apply_field_level_auth(
  Ash.Resource.t(),
  Ash.Resource.Record.t() | [Ash.Resource.Record.t()],
  Keyword.t()
) ::
  {:ok, Ash.Resource.Record.t() | [Ash.Resource.Record.t()]}
  | {:error, Ash.Error.t()}

Apply field-level authorization to records that are already in memory, scrubbing any fields the actor isn't allowed to see.

Walks each authorizer configured on the resource and invokes its apply_field_level_auth/3 callback if defined. Returns the records with forbidden fields replaced by %Ash.ForbiddenField{}.

Use this when you have records in hand (for example, returned from a generic action or constructed in memory) and want field policies applied without driving the records through a full read.

Supported options:

  • :actor - the actor whose visibility is being checked.
  • :tenant - the tenant the records belong to.
  • :domain - the domain context.