Ash.Authorizer behaviour (ash v3.27.8)

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

Callbacks

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

Returns the fields this authorizer may protect at field level for the resource.

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)

protected_fields(t)

(optional)
@callback protected_fields(Ash.Resource.t()) :: [atom()]

Returns the fields this authorizer may protect at field level for the resource.

This is metadata for callers that need to know which fields can be hidden by authorization without running an action. Authorizers that do not implement this callback are treated as protecting no fields.

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.