Stack-agnostic authorization seam for production operator access and future destructive actions.
This behaviour is the stable adopter-owned auth seam for mailglass_admin.
If your app integrates with the operator surface, this is the module contract
to depend on.
Adopters implement this behaviour and pass the module to
mailglass_operator_routes/2. MailglassAdmin normalizes the return
shape so later operator actions can rely on one server-side contract.
Sensitive operator actions stay adopter-owned. For example, an adopter
may choose to require a recent reauthentication check before allowing
:destructive_action:
def authorize(:destructive_action, %{actor: %{recent_auth_at: recent_auth_at}})
when is_struct(recent_auth_at, DateTime) do
if DateTime.diff(DateTime.utc_now(), recent_auth_at, :second) <= 900 do
{:ok, %{subject_id: "operator-1", recent_auth_at: recent_auth_at}}
else
{:error, :stale_auth, %{message: "Recent authentication is required."}}
end
endThe 900-second window above is an adopter example, not a library-owned constant or policy.
Summary
Types
@type action() :: :operator_access | :destructive_action | atom()
@type actor() :: %{ :subject_id => term(), optional(:tenant_id) => term() | nil, optional(:auth_method) => String.t() | atom() | nil, optional(:recent_auth_at) => DateTime.t() | nil }
@type failure() :: {:error, failure_reason(), map()}
@type failure_reason() :: :unauthorized | :stale_auth