Attesto.StepUp (Attesto v0.13.0)

Copy Markdown View Source

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.

Summary

Types

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

Functions

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 verified token claims against requirement at now (unix seconds).

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

Types

challenge()

@type challenge() :: %{
  optional(:acr_values) => String.t(),
  optional(:max_age) => non_neg_integer()
}

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

Functions

challenge_params(requirement)

@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(requirement, claims, now)

@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?(requirement, claims, now)

@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).