fix(oauth): respect oauth-protected-resource discovery (#511)

This commit is contained in:
Gabriel Peal 2025-11-05 06:19:13 -08:00 committed by GitHub
parent 101b8ad84f
commit 82f9b0976a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -615,7 +615,7 @@ impl AuthorizationManager {
async fn discover_oauth_server_via_resource_metadata(
&self,
) -> Result<Option<AuthorizationMetadata>, AuthError> {
let Some(resource_metadata_url) = self.fetch_resource_metadata_url().await? else {
let Some(resource_metadata_url) = self.discover_resource_metadata_url().await? else {
return Ok(None);
};
@ -667,12 +667,38 @@ impl AuthorizationManager {
Ok(None)
}
async fn discover_resource_metadata_url(&self) -> Result<Option<Url>, AuthError> {
if let Ok(Some(resource_metadata_url)) =
self.fetch_resource_metadata_url(&self.base_url).await
{
return Ok(Some(resource_metadata_url));
}
// If the primary URL doesn't use WWW-Authenticate, try oauth-protected-resource discovery.
// https://www.rfc-editor.org/rfc/rfc9728.html#name-obtaining-protected-resourc
for candidate_path in
Self::well_known_paths(self.base_url.path(), "oauth-protected-resource")
{
let mut discovery_url = self.base_url.clone();
discovery_url.set_query(None);
discovery_url.set_fragment(None);
discovery_url.set_path(&candidate_path);
if let Ok(Some(resource_metadata_url)) =
self.fetch_resource_metadata_url(&discovery_url).await
{
return Ok(Some(resource_metadata_url));
}
}
Ok(None)
}
/// Extract the resource metadata url from the WWW-Authenticate header value.
/// https://www.rfc-editor.org/rfc/rfc9728.html#name-use-of-www-authenticate-for
async fn fetch_resource_metadata_url(&self) -> Result<Option<Url>, AuthError> {
async fn fetch_resource_metadata_url(&self, url: &Url) -> Result<Option<Url>, AuthError> {
let response = match self
.http_client
.get(self.base_url.clone())
.get(url.clone())
.header("MCP-Protocol-Version", "2024-11-05")
.send()
.await
@ -684,7 +710,9 @@ impl AuthorizationManager {
}
};
if response.status() != StatusCode::UNAUTHORIZED {
if response.status() == StatusCode::OK {
return Ok(Some(url.clone()));
} else if response.status() != StatusCode::UNAUTHORIZED {
debug!(
"resource metadata probe returned unexpected status: {}",
response.status()