# `MailglassAdmin.Auth`
[🔗](https://github.com/szTheory/mailglass/blob/v1.0.0/lib/mailglass_admin/auth.ex#L1)

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
    end

The 900-second window above is an adopter example, not a library-owned
constant or policy.

# `action`
*since 0.1.0* 

```elixir
@type action() :: :operator_access | :destructive_action | atom()
```

# `actor`
*since 0.1.0* 

```elixir
@type actor() :: %{
  :subject_id =&gt; term(),
  optional(:tenant_id) =&gt; term() | nil,
  optional(:auth_method) =&gt; String.t() | atom() | nil,
  optional(:recent_auth_at) =&gt; DateTime.t() | nil
}
```

# `failure`
*since 0.1.0* 

```elixir
@type failure() :: {:error, failure_reason(), map()}
```

# `failure_reason`
*since 0.1.0* 

```elixir
@type failure_reason() :: :unauthorized | :stale_auth
```

# `result`
*since 0.1.0* 

```elixir
@type result() :: success() | failure()
```

# `success`
*since 0.1.0* 

```elixir
@type success() ::
  {:ok, actor()} | {:ok, %{:actor =&gt; actor(), optional(:assigns) =&gt; map()}}
```

# `authorize`
*since 0.1.0* 

```elixir
@callback authorize(action(), context :: map()) :: result()
```

# `authorize`
*since 0.1.0* 

```elixir
@spec authorize(module(), action(), map()) ::
  {:ok, %{actor: actor(), assigns: map()}} | failure()
```

# `session_actor`
*since 0.1.0* 

```elixir
@spec session_actor(map()) :: actor()
```

---

*Consult [api-reference.md](api-reference.md) for complete listing*
