Skip to content

Commit 82f9b09

Browse files
authored
fix(oauth): respect oauth-protected-resource discovery (#511)
1 parent 101b8ad commit 82f9b09

File tree

1 file changed

+32
-4
lines changed

1 file changed

+32
-4
lines changed

crates/rmcp/src/transport/auth.rs

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -615,7 +615,7 @@ impl AuthorizationManager {
615615
async fn discover_oauth_server_via_resource_metadata(
616616
&self,
617617
) -> Result<Option<AuthorizationMetadata>, AuthError> {
618-
let Some(resource_metadata_url) = self.fetch_resource_metadata_url().await? else {
618+
let Some(resource_metadata_url) = self.discover_resource_metadata_url().await? else {
619619
return Ok(None);
620620
};
621621

@@ -667,12 +667,38 @@ impl AuthorizationManager {
667667
Ok(None)
668668
}
669669

670+
async fn discover_resource_metadata_url(&self) -> Result<Option<Url>, AuthError> {
671+
if let Ok(Some(resource_metadata_url)) =
672+
self.fetch_resource_metadata_url(&self.base_url).await
673+
{
674+
return Ok(Some(resource_metadata_url));
675+
}
676+
677+
// If the primary URL doesn't use WWW-Authenticate, try oauth-protected-resource discovery.
678+
// https://www.rfc-editor.org/rfc/rfc9728.html#name-obtaining-protected-resourc
679+
for candidate_path in
680+
Self::well_known_paths(self.base_url.path(), "oauth-protected-resource")
681+
{
682+
let mut discovery_url = self.base_url.clone();
683+
discovery_url.set_query(None);
684+
discovery_url.set_fragment(None);
685+
discovery_url.set_path(&candidate_path);
686+
if let Ok(Some(resource_metadata_url)) =
687+
self.fetch_resource_metadata_url(&discovery_url).await
688+
{
689+
return Ok(Some(resource_metadata_url));
690+
}
691+
}
692+
693+
Ok(None)
694+
}
695+
670696
/// Extract the resource metadata url from the WWW-Authenticate header value.
671697
/// https://www.rfc-editor.org/rfc/rfc9728.html#name-use-of-www-authenticate-for
672-
async fn fetch_resource_metadata_url(&self) -> Result<Option<Url>, AuthError> {
698+
async fn fetch_resource_metadata_url(&self, url: &Url) -> Result<Option<Url>, AuthError> {
673699
let response = match self
674700
.http_client
675-
.get(self.base_url.clone())
701+
.get(url.clone())
676702
.header("MCP-Protocol-Version", "2024-11-05")
677703
.send()
678704
.await
@@ -684,7 +710,9 @@ impl AuthorizationManager {
684710
}
685711
};
686712

687-
if response.status() != StatusCode::UNAUTHORIZED {
713+
if response.status() == StatusCode::OK {
714+
return Ok(Some(url.clone()));
715+
} else if response.status() != StatusCode::UNAUTHORIZED {
688716
debug!(
689717
"resource metadata probe returned unexpected status: {}",
690718
response.status()

0 commit comments

Comments
 (0)