Skip to content

Commit bce0555

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

File tree

2 files changed

+21
-2
lines changed

2 files changed

+21
-2
lines changed

crates/rmcp/src/transport/auth.rs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,14 +154,15 @@ pub enum AuthError {
154154
}
155155

156156
/// oauth2 metadata
157-
#[derive(Debug, Clone, Deserialize, Serialize)]
157+
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
158158
pub struct AuthorizationMetadata {
159159
pub authorization_endpoint: String,
160160
pub token_endpoint: String,
161161
pub registration_endpoint: Option<String>,
162162
pub issuer: Option<String>,
163163
pub jwks_uri: Option<String>,
164164
pub scopes_supported: Option<Vec<String>>,
165+
pub response_types_supported: Option<Vec<String>>,
165166
// allow additional fields
166167
#[serde(flatten)]
167168
pub additional_fields: HashMap<String, serde_json::Value>,
@@ -379,7 +380,17 @@ impl AuthorizationManager {
379380
self.oauth_client = Some(client_builder);
380381
Ok(())
381382
}
382-
383+
/// validate if the server support the response type
384+
fn validate_response_supported(&self, response_type: &str) -> Result<(), AuthError> {
385+
if let Some(metadata) = self.metadata.as_ref() {
386+
if let Some(response_types_supported) = metadata.response_types_supported.as_ref() {
387+
if !response_types_supported.contains(&response_type.to_string()) {
388+
return Err(AuthError::InvalidScope(response_type.to_string()));
389+
}
390+
}
391+
}
392+
Ok(())
393+
}
383394
/// dynamic register oauth2 client
384395
pub async fn register_client(
385396
&mut self,
@@ -397,6 +408,10 @@ impl AuthorizationManager {
397408
));
398409
};
399410

411+
// RFC 8414 RECOMMENDS response_types_supported in the metadata. This field is optional,
412+
// but if present and does not include the flow we use ("code"), bail out early with a clear error.
413+
self.validate_response_supported("code")?;
414+
400415
let registration_request = ClientRegistrationRequest {
401416
client_name: name.to_string(),
402417
redirect_uris: vec![redirect_uri.to_string()],
@@ -485,6 +500,9 @@ impl AuthorizationManager {
485500
.as_ref()
486501
.ok_or_else(|| AuthError::InternalError("OAuth client not configured".to_string()))?;
487502

503+
// ensure the server supports the response type we intend to use when metadata is available
504+
self.validate_response_supported("code")?;
505+
488506
// generate pkce challenge
489507
let (pkce_challenge, pkce_verifier) = PkceCodeChallenge::new_random_sha256();
490508

examples/servers/src/complex_auth_streamhttp.rs

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

0 commit comments

Comments
 (0)