Skip to content

Commit 3c5ce2b

Browse files
authored
fix(auth): align OAuth metadata discovery ordering (#887)
1 parent 443677c commit 3c5ce2b

2 files changed

Lines changed: 47 additions & 1 deletion

File tree

crates/rmcp/src/transport/auth.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1508,7 +1508,7 @@ impl AuthorizationManager {
15081508
push_candidate("/.well-known/oauth-authorization-server".to_string());
15091509
push_candidate("/.well-known/openid-configuration".to_string());
15101510
} else {
1511-
// Path components present: follow spec priority order
1511+
// Path components present: prefer OAuth discovery before OpenID Connect fallbacks.
15121512
// 1. OAuth 2.0 with path insertion
15131513
push_candidate(format!("/.well-known/oauth-authorization-server/{trimmed}"));
15141514
// 2. OpenID Connect with path insertion

crates/rmcp/tests/test_client_credentials.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,25 @@ async fn start_mock_server() -> (String, SocketAddr) {
136136
(base_url, addr)
137137
}
138138

139+
async fn start_path_insert_metadata_server() -> (String, SocketAddr) {
140+
let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap();
141+
let addr = listener.local_addr().unwrap();
142+
let base_url = format!("http://{}", addr);
143+
144+
let app = Router::new()
145+
.route(
146+
"/.well-known/oauth-authorization-server/mcp",
147+
get(auth_server_metadata_handler),
148+
)
149+
.route("/token", post(token_handler));
150+
151+
tokio::spawn(async move {
152+
axum::serve(listener, app).await.unwrap();
153+
});
154+
155+
(base_url, addr)
156+
}
157+
139158
#[tokio::test]
140159
async fn test_client_credentials_flow_client_secret() {
141160
let (base_url, _addr) = start_mock_server().await;
@@ -162,6 +181,33 @@ async fn test_client_credentials_flow_client_secret() {
162181
assert_eq!(token, "m2m-access-token-12345");
163182
}
164183

184+
#[tokio::test]
185+
async fn test_client_credentials_discovers_path_inserted_oauth_metadata() {
186+
let (base_url, _addr) = start_path_insert_metadata_server().await;
187+
let resource_url = format!("{base_url}/mcp");
188+
189+
let mut oauth_state = OAuthState::new(&resource_url, None).await.unwrap();
190+
191+
let config = ClientCredentialsConfig::ClientSecret {
192+
client_id: "test-m2m-client".to_string(),
193+
client_secret: "test-m2m-secret".to_string(),
194+
scopes: vec!["read".to_string()],
195+
resource: Some(resource_url),
196+
};
197+
198+
oauth_state
199+
.authenticate_client_credentials(config)
200+
.await
201+
.unwrap();
202+
203+
let manager = oauth_state
204+
.into_authorization_manager()
205+
.expect("Should be in Authorized state");
206+
207+
let token = manager.get_access_token().await.unwrap();
208+
assert_eq!(token, "m2m-access-token-12345");
209+
}
210+
165211
#[tokio::test]
166212
async fn test_client_credentials_invalid_secret() {
167213
let (base_url, _addr) = start_mock_server().await;

0 commit comments

Comments
 (0)