Harden MCP OAuth callback handling (#40691)

## Why

MCP servers can share an OAuth callback URL. Without a validated issuer or a
server-specific callback path, an authorization response could be associated
with the wrong server.

## What changed

- Use stable callbacks when authorization metadata advertises issuer-bound
  responses, and validate the returned issuer before exchanging the code.
- Retain server-specific callback IDs for providers without issuer support,
  including fallback to the global or default callback for legacy registered
  clients.
- Persist registered callback URLs for MCP servers and plugins, and insert the
  active listener port into portless loopback redirects.

## Testing

Add coverage for issuer validation, callback-mode discovery, registered and
legacy clients, plugin OAuth, CLI persistence, and loopback listener ports.

GitOrigin-RevId: 2878c92e237fc17fd3def0bd2e1cce3e104a3db8
This commit is contained in:
stevenlee-oai authored and copyberry committed 2026-08-25 20:26:23 +00:00
1 parent 32ce703a80
commit 9be8d6e1c3
28 files changed
+1096 -127

No files matched your search

+4
View File
@@ -146,6 +146,10 @@ pub struct McpServerOAuthConfig {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub client_id: Option<String>,
/// Registered callback URL associated with this OAuth client.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub callback_url: Option<String>,
/// Fixed callback port that takes precedence over Codex's global OAuth callback port.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub callback_port: Option<u16>,
+2
View File
@@ -364,6 +364,7 @@ fn deserialize_streamable_http_server_config_with_oauth_client_id() {
[oauth]
client_id = "eci-prd-pub-codex-123"
callback_url = "http://127.0.0.1/callback/registered"
callback_port = 9876
"#,
)
@@ -373,6 +374,7 @@ fn deserialize_streamable_http_server_config_with_oauth_client_id() {
cfg.oauth,
Some(McpServerOAuthConfig {
client_id: Some("eci-prd-pub-codex-123".to_string()),
callback_url: Some("http://127.0.0.1/callback/registered".to_string()),
callback_port: Some(9876),
})
);