# `Attesto.Plug.OAuthError`
[🔗](https://github.com/XukuLLC/attesto/blob/v0.13.0/lib/attesto/plug/oauth_error.ex#L2)

Render the RFC 6750 / RFC 9449 error responses for the Attesto plugs.

Translates the verifier's error atoms into the wire responses a
protected resource owes a client:

  * `invalid_token` (RFC 6750 §3.1) - 401 with a `WWW-Authenticate`
    challenge for the scheme the request used (`Bearer` or `DPoP`).
  * `invalid_dpop_proof` (RFC 9449 §7.1) - 401 with a `DPoP`
    challenge, for a DPoP proof that failed verification.
  * `use_dpop_nonce` (RFC 9449 §8) - 401 with a `DPoP` challenge and a
    fresh `DPoP-Nonce` header, telling the client to retry with the
    nonce.
  * `insufficient_scope` (RFC 6750 §3.1) - 403 naming the required
    scope.

Each helper sets the status, the `WWW-Authenticate` header (and
`DPoP-Nonce` when relevant), writes a small JSON body, and halts the
pipeline. Hosts may override only the transport details with `:send_error`,
`:www_authenticate`, and `:no_store` callbacks; the OAuth error code,
status, and challenge semantics remain owned here. This module is part of
the optional `Attesto.Plug` layer; it only compiles when `Plug` is
available.

# `scheme`

```elixir
@type scheme() :: :bearer | :dpop
```

# `insufficient_scope`

```elixir
@spec insufficient_scope(Plug.Conn.t(), [String.t()], scheme(), keyword()) ::
  Plug.Conn.t()
```

Respond 403 `insufficient_scope` naming the `required` scope list
(RFC 6750 §3.1). The optional `opts` accepts `:resource_metadata` (RFC 9728
§5.1: the URL of this resource's protected-resource metadata, advertised as
a `resource_metadata` auth-param) and the SAME transport hooks
`unauthorized/4` honors - `:send_error`, `:www_authenticate`, and
`:no_store` - so a resource server can override the 403 response envelope and
inject a per-conn challenge (e.g. a host-derived `resource_metadata` pointer)
on the scope-rejection path too. The `insufficient_scope` error code, 403
status, and the `error_description` / `scope` challenge semantics remain
owned here. Halts.

# `insufficient_user_authentication`

```elixir
@spec insufficient_user_authentication(Plug.Conn.t(), scheme(), map(), keyword()) ::
  Plug.Conn.t()
```

Respond RFC 9470 §3 `insufficient_user_authentication` (401): the presented
token does not meet the route's step-up requirement.

`challenge` is the `Attesto.StepUp` challenge map carrying the `:acr_values`
(space-delimited) and/or `:max_age` the client must re-request at the
authorization endpoint; both are appended as `WWW-Authenticate` auth-params.
This is an *authentication* error (401, like `invalid_token`), built on the
same machinery as `unauthorized/4`, honoring the same `:description`,
`:resource_metadata`, and `:send_error` / `:www_authenticate` / `:no_store`
transport hooks. Halts.

# `unauthorized`

```elixir
@spec unauthorized(Plug.Conn.t(), scheme(), String.t(), keyword()) :: Plug.Conn.t()
```

Respond 401 with a `WWW-Authenticate` challenge for `scheme` carrying
`error` (an OAuth error code string). Options: `:description`
(`error_description`), `:dpop_nonce` (sets the `DPoP-Nonce` header, for
`use_dpop_nonce`), and `:resource_metadata` (RFC 9728 §5.1: the URL of this
resource's protected-resource metadata, advertised as a `resource_metadata`
auth-param so the client can discover the authorization server). Halts.

---

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