# `Attesto.StepUp`
[🔗](https://github.com/XukuLLC/attesto/blob/v0.13.0/lib/attesto/step_up.ex#L61)

RFC 9470 Step-Up Authentication Challenge — the conn-free core primitive.

A resource server that needs a fresher or stronger end-user authentication for
a sensitive operation evaluates the presented (already verified) access token
against an `Attesto.StepUp.Requirement` and, when it is not satisfied, answers
RFC 9470 §3 `WWW-Authenticate: Bearer error="insufficient_user_authentication"`
with the `acr_values` / `max_age` the client must re-request at the
authorization endpoint.

This module is conn-free: it reads only the token's `acr` / `auth_time` claims
and a caller-supplied `now`, decides satisfaction (the framing layer renders
the challenge), and never touches a `Plug.Conn`, a store, or a wall clock.

## Semantics

  * The two dimensions are a **conjunction** (RFC 9470 §4): the token must
    satisfy the `acr` set membership AND the `auth_time` freshness bound.
  * **Fail-closed**: a token whose `acr` is absent/non-string (when an
    `acr_values` set is required), or whose `auth_time` is absent/non-integer
    (when a `max_age` is required), does NOT satisfy the requirement. A token
    from a non-OIDC grant (no `auth_time`) therefore always challenges a
    freshness requirement — step-up routes are for end-user grants.

# `challenge`

```elixir
@type challenge() :: %{
  optional(:acr_values) =&gt; String.t(),
  optional(:max_age) =&gt; non_neg_integer()
}
```

The RFC 9470 §3 challenge parameters naming what the client must re-request.

# `challenge_params`

```elixir
@spec challenge_params(Attesto.StepUp.Requirement.t()) :: challenge()
```

The RFC 9470 §3 challenge parameters for `requirement`: `:acr_values`
(space-delimited) and/or `:max_age`. Transport-free — the plug owns the
`WWW-Authenticate` scheme (Bearer vs DPoP) and quoting.

# `evaluate`

```elixir
@spec evaluate(Attesto.StepUp.Requirement.t(), map(), integer()) ::
  :ok | {:error, :insufficient_user_authentication, challenge()}
```

Evaluate verified token `claims` against `requirement` at `now` (unix seconds).

Returns `:ok`, or `{:error, :insufficient_user_authentication, challenge}` where
`challenge` carries the `acr_values` (space-delimited) / `max_age` the client
must re-request.

# `satisfied?`

```elixir
@spec satisfied?(Attesto.StepUp.Requirement.t(), map(), integer()) :: boolean()
```

Whether the token's `acr` / `auth_time` claims satisfy `requirement` at `now`
(the conjunction of both dimensions; fail-closed on absent/malformed claims).

---

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