Parse and format WWW-Authenticate challenges (RFC 9110 §11.6.1), as used
by the MCP authorization spec to point clients at protected-resource
metadata and signal insufficient_scope step-up.
Summary
Functions
Build a Bearer challenge from a keyword list, dropping nil values.
Escape a value for a quoted-string (RFC 9110 §5.6.4).
Format a challenge header value. params is an enumerable of name/value
pairs; values are escaped with escape_quoted/1, so a value carrying CR/LF
raises rather than splitting the response header.
Parse a challenge header value.
Types
Functions
Build a Bearer challenge from a keyword list, dropping nil values.
Ordering is preserved, so callers control how the challenge reads:
iex> Noizu.MCP.Auth.WWWAuthenticate.bearer_challenge(
...> resource_metadata: "https://x/.well-known/oauth-protected-resource",
...> scope: nil,
...> error: "invalid_token"
...> )
~s(Bearer resource_metadata="https://x/.well-known/oauth-protected-resource", error="invalid_token")
Escape a value for a quoted-string (RFC 9110 §5.6.4).
Backslash and double quote are escaped. CR, LF, NUL and any other control
character are rejected — they cannot be represented in a quoted-string
and are the header-injection vector — so this raises ArgumentError rather
than emitting a header an attacker chose the shape of. The raised message
never includes the offending value.
iex> Noizu.MCP.Auth.WWWAuthenticate.escape_quoted(~s(a"b\\c))
~S(a\"b\\c)
Format a challenge header value. params is an enumerable of name/value
pairs; values are escaped with escape_quoted/1, so a value carrying CR/LF
raises rather than splitting the response header.
Parse a challenge header value.
iex> Noizu.MCP.Auth.WWWAuthenticate.parse(
...> ~s(Bearer resource_metadata="https://x/.well-known/oauth-protected-resource", error="invalid_token")
...> )
%Noizu.MCP.Auth.WWWAuthenticate{
scheme: "Bearer",
params: %{
"resource_metadata" => "https://x/.well-known/oauth-protected-resource",
"error" => "invalid_token"
}
}