# `Snodo.Client.Challenge`
[🔗](https://github.com/joshrotenberg/snodo/blob/v0.4.1/lib/snodo/client/challenge.ex#L1)

One authentication challenge from a `WWW-Authenticate` response header.

A 401 or 403 from an MCP server over HTTP carries the challenge that tells
a client how to authorize (RFC 9110 section 11.6.1, RFC 6750 section 3, and
the MCP authorization specification):

    WWW-Authenticate: Bearer resource_metadata="https://mcp.example.com/.well-known/oauth-protected-resource/mcp", scope="mcp:read"
    WWW-Authenticate: Bearer error="insufficient_scope", scope="mcp:write"

`parse/1` reads every challenge in one header value. `select/1` picks the
challenge a token provider acts on from a response's headers. The struct
keeps every parameter in `params`, keyed by lowercase name, and lifts the
ones the MCP flow reads:

  * `resource_metadata` - the URL of the protected resource metadata
    document (RFC 9728).
  * `scope` - the scopes the server asks for, split on spaces.
  * `error` and `error_description` - the RFC 6750 error, for example
    `"invalid_token"` or `"insufficient_scope"`.

A header longer than 8 KiB, or one that does not follow the grammar, parses
as no challenges. A parameter that appears twice keeps its first value. A
challenge that carries a token68 credential instead of parameters, such as
`Negotiate abc==`, has empty `params`, and the challenges after it are
still read.

# `t`

```elixir
@type t() :: %Snodo.Client.Challenge{
  error: String.t() | nil,
  error_description: String.t() | nil,
  params: %{optional(String.t()) =&gt; String.t()},
  resource_metadata: String.t() | nil,
  scheme: String.t(),
  scope: [String.t()]
}
```

# `parse`

```elixir
@spec parse(String.t()) :: [t()]
```

Parses one `WWW-Authenticate` header value into its challenges, in order.

Parameter values may be tokens or quoted strings; a quoted string is
unescaped. Schemes and parameter names are lowercased. An empty list means
the header carries no usable challenge.

# `select`

```elixir
@spec select([{String.t(), String.t()}]) :: t() | nil
```

Picks the challenge to act on from a response's `{name, value}` headers.

Every `www-authenticate` header (compared without case) is parsed. The
first `Bearer` challenge wins; without one, the first challenge of any
scheme is returned, so a provider can report that it does not support the
scheme. `nil` when the response carries no challenge.

---

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