mirror of
https://github.com/openai/codex.git
synced 2026-11-11 21:10:39 +00:00
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:
@@ -28,6 +28,7 @@ use codex_core_plugins::remote_bundle::RemotePluginBundleInstallError;
|
||||
use codex_mcp::McpOAuthLoginSupport;
|
||||
use codex_mcp::McpRuntimeContext;
|
||||
use codex_mcp::oauth_login_support;
|
||||
use codex_mcp::resolve_oauth_callback;
|
||||
use codex_mcp::should_retry_without_scopes;
|
||||
use codex_plugin::PluginId;
|
||||
use codex_plugin::PluginTelemetryMetadata;
|
||||
@@ -1943,12 +1944,25 @@ impl PluginRequestProcessor {
|
||||
let store_mode = config.mcp_oauth_credentials_store_mode;
|
||||
let keyring_backend_kind = config.auth_keyring_backend_kind();
|
||||
let callback_port = server.oauth_callback_port(config.mcp_oauth_callback_port);
|
||||
let callback_url = config.mcp_oauth_callback_url.clone();
|
||||
let callback_url = match resolve_oauth_callback(
|
||||
&server,
|
||||
&oauth_config.url,
|
||||
config.mcp_oauth_callback_url.as_deref(),
|
||||
) {
|
||||
Ok(callback_url) => callback_url,
|
||||
Err(error) => {
|
||||
warn!(
|
||||
"failed to resolve MCP OAuth callback for plugin install {name}: {error}"
|
||||
);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let outgoing = Arc::clone(&self.outgoing);
|
||||
let notification_name = name.clone();
|
||||
let oauth_credential_name = server.oauth_credential_name(&name).into_owned();
|
||||
let thread_manager = Arc::clone(&self.thread_manager);
|
||||
let http_client = Arc::clone(&http_client);
|
||||
let global_callback_url = config.mcp_oauth_callback_url.clone();
|
||||
|
||||
tokio::spawn(async move {
|
||||
let oauth_client_id = server.oauth_client_id();
|
||||
@@ -1965,6 +1979,7 @@ impl PluginRequestProcessor {
|
||||
server.oauth_resource.as_deref(),
|
||||
callback_port,
|
||||
callback_url.as_deref(),
|
||||
global_callback_url.as_deref(),
|
||||
Arc::clone(&http_client),
|
||||
redirect_mode,
|
||||
)
|
||||
@@ -1985,6 +2000,7 @@ impl PluginRequestProcessor {
|
||||
server.oauth_resource.as_deref(),
|
||||
callback_port,
|
||||
callback_url.as_deref(),
|
||||
global_callback_url.as_deref(),
|
||||
http_client,
|
||||
redirect_mode,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user