Skip to content

Commit 78f73e1

Browse files
committed
fix(oauth): rfc8414 should judement the response_types
response_types_supported should be judement while try to do 'Authorization Code Flow' Signed-off-by: jokemanfire <[email protected]>
1 parent a211a71 commit 78f73e1

File tree

2 files changed

+22
-7
lines changed

2 files changed

+22
-7
lines changed

crates/rmcp/src/transport/auth.rs

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -98,14 +98,15 @@ pub enum AuthError {
9898
}
9999

100100
/// oauth2 metadata
101-
#[derive(Debug, Clone, Deserialize, Serialize)]
101+
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
102102
pub struct AuthorizationMetadata {
103103
pub authorization_endpoint: String,
104104
pub token_endpoint: String,
105105
pub registration_endpoint: Option<String>,
106106
pub issuer: Option<String>,
107107
pub jwks_uri: Option<String>,
108108
pub scopes_supported: Option<Vec<String>>,
109+
pub response_types_supported: Option<Vec<String>>,
109110
// allow additional fields
110111
#[serde(flatten)]
111112
pub additional_fields: HashMap<String, serde_json::Value>,
@@ -290,11 +291,7 @@ impl AuthorizationManager {
290291
Ok(AuthorizationMetadata {
291292
authorization_endpoint: create_endpoint("authorize"),
292293
token_endpoint: create_endpoint("token"),
293-
registration_endpoint: None,
294-
issuer: None,
295-
jwks_uri: None,
296-
scopes_supported: None,
297-
additional_fields: HashMap::new(),
294+
..Default::default()
298295
})
299296
}
300297

@@ -339,7 +336,17 @@ impl AuthorizationManager {
339336
self.oauth_client = Some(client_builder);
340337
Ok(())
341338
}
342-
339+
/// validate if the server support the response type
340+
fn validate_response_supported(&self, response_type: &str) -> Result<(), AuthError> {
341+
if let Some(metadata) = self.metadata.as_ref() {
342+
if let Some(response_types_supported) = metadata.response_types_supported.as_ref() {
343+
if !response_types_supported.contains(&response_type.to_string()) {
344+
return Err(AuthError::InvalidScope(response_type.to_string()));
345+
}
346+
}
347+
}
348+
Ok(())
349+
}
343350
/// dynamic register oauth2 client
344351
pub async fn register_client(
345352
&mut self,
@@ -357,6 +364,10 @@ impl AuthorizationManager {
357364
));
358365
};
359366

367+
// RFC 8414 RECOMMENDS response_types_supported in the metadata. This field is optional,
368+
// but if present and does not include the flow we use ("code"), bail out early with a clear error.
369+
self.validate_response_supported("code")?;
370+
360371
// prepare registration request
361372
let registration_request = ClientRegistrationRequest {
362373
client_name: name.to_string(),
@@ -446,6 +457,9 @@ impl AuthorizationManager {
446457
.as_ref()
447458
.ok_or_else(|| AuthError::InternalError("OAuth client not configured".to_string()))?;
448459

460+
// ensure the server supports the response type we intend to use when metadata is available
461+
self.validate_response_supported("code")?;
462+
449463
// generate pkce challenge
450464
let (pkce_challenge, pkce_verifier) = PkceCodeChallenge::new_random_sha256();
451465

examples/servers/src/complex_auth_sse.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,7 @@ async fn oauth_authorization_server() -> impl IntoResponse {
526526
token_endpoint: format!("http://{}/oauth/token", BIND_ADDRESS),
527527
scopes_supported: Some(vec!["profile".to_string(), "email".to_string()]),
528528
registration_endpoint: Some(format!("http://{}/oauth/register", BIND_ADDRESS)),
529+
response_types_supported: Some(vec!["code".to_string()]),
529530
issuer: Some(BIND_ADDRESS.to_string()),
530531
jwks_uri: Some(format!("http://{}/oauth/jwks", BIND_ADDRESS)),
531532
additional_fields,

0 commit comments

Comments
 (0)