pub fn parse_www_authenticate_param(www_auth: &str, param_name: &str) -> Option<String> {
let body = www_auth.trim_start();
let body = body
.strip_prefix("Bearer")
.or_else(|| body.strip_prefix("bearer"))
.or_else(|| body.strip_prefix("Basic"))
.or_else(|| body.strip_prefix("basic"))
.unwrap_or(body);
let prefix = format!("{}=", param_name);
for part in body.split(',') {
let trimmed = part.trim();
if let Some(rest) = trimmed.strip_prefix(&prefix) {
let value = rest.trim().trim_matches('"');
if !value.is_empty() {
return Some(value.to_string());
}
}
}
None
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parses_bearer_scope() {
let h = r#"Bearer scope="mcp:read""#;
assert_eq!(
parse_www_authenticate_param(h, "scope"),
Some("mcp:read".into())
);
}
#[test]
fn parses_multiple_params() {
let h = r#"Bearer scope="mcp:read mcp:write", error="insufficient_scope""#;
assert_eq!(
parse_www_authenticate_param(h, "scope"),
Some("mcp:read mcp:write".into())
);
assert_eq!(
parse_www_authenticate_param(h, "error"),
Some("insufficient_scope".into())
);
}
#[test]
fn parses_resource_metadata_url() {
let h = r#"Bearer resource_metadata="https://example.com/.well-known/oauth-protected-resource""#;
assert_eq!(
parse_www_authenticate_param(h, "resource_metadata"),
Some("https://example.com/.well-known/oauth-protected-resource".into())
);
}
#[test]
fn missing_param_returns_none() {
let h = r#"Bearer scope="mcp:read""#;
assert_eq!(parse_www_authenticate_param(h, "error"), None);
}
#[test]
fn empty_value_returns_none() {
let h = r#"Bearer scope="""#;
assert_eq!(parse_www_authenticate_param(h, "scope"), None);
}
#[test]
fn handles_no_scheme_prefix() {
let h = r#"scope="mcp:read""#;
assert_eq!(
parse_www_authenticate_param(h, "scope"),
Some("mcp:read".into())
);
}
#[test]
fn handles_lowercase_scheme() {
let h = r#"bearer scope="mcp:read""#;
assert_eq!(
parse_www_authenticate_param(h, "scope"),
Some("mcp:read".into())
);
}
#[test]
fn handles_unquoted_value() {
let h = r#"Bearer error=invalid_token"#;
assert_eq!(
parse_www_authenticate_param(h, "error"),
Some("invalid_token".into())
);
}
}