Use runtime authentication for OpenAI MCP and app requests (#59749)

## What changed

- Select fresh authentication for each HTTP operation on eligible OpenAI MCP connections while preserving the connection's credential source and account network policy. Stop redirects when requests carry runtime assertions.
- Pass the owning thread's authentication and runtime context through app discovery, connector metadata, and trusted-access requests. Include the runtime authentication mode in MCP connection and tool-cache identities.
- Give resumed actors analytics clients bound to their own authentication context, and serialize stored-credential reloads with token refresh while preserving host-provided credentials.

## Testing

Add coverage for fresh request assertions, revoked account policies, redirect handling, resumed-actor isolation, and MCP uploads in dual-header and assertion-only modes.

GitOrigin-RevId: f06900a6db61cd6cf53c3aa8075afeec4d5706d9
This commit is contained in:
cooper-oai
2026-11-05 22:03:29 +00:00
committed by copyberry
parent e934edd68c
commit 219ab4043e
51 changed files with 1901 additions and 250 deletions
+51 -3
View File
@@ -915,6 +915,21 @@ impl ThreadManager {
.map(|runtime| (runtime, config.runtime_auth_mode)))
}
/// Initialize the selected thread owner's runtime, including after a feature enablement.
pub fn runtime_auth_for_mcp_manager(
&self,
config: &Config,
mcp_manager: &McpManager,
) -> std::io::Result<Option<(Arc<RuntimeAuthManager>, codex_features::RuntimeAuthMode)>> {
Ok(crate::runtime_auth::runtime_for_config(
&mcp_manager.plugins_manager().runtime_auth_slot(),
config,
mcp_manager.auth_manager(),
&self.state.installation_id,
)
.map(|runtime| (runtime, config.runtime_auth_mode)))
}
pub fn skills_service(&self) -> Arc<HostSkillsService> {
self.state.skills_service.clone()
}
@@ -2611,10 +2626,14 @@ impl ThreadManagerState {
codex_sandboxing::WindowsSandboxProxySettingsMode::Reconcile
};
// A resumed actor and its descendants share an owner, not the harness default's credentials.
let (runtime_auth, plugins_manager) = if Arc::ptr_eq(&auth_manager, &self.auth_manager) {
let (runtime_auth, plugins_manager, analytics_events_client) = if Arc::ptr_eq(
&auth_manager,
&self.auth_manager,
) {
(
inherited_runtime_auth.unwrap_or_else(|| Arc::clone(&self.runtime_auth)),
Arc::clone(&self.plugins_manager),
self.analytics_events_client.clone(),
)
} else {
let threads = self.threads.read().await;
@@ -2627,6 +2646,7 @@ impl ThreadManagerState {
inherited_runtime_auth
.unwrap_or_else(|| Arc::clone(&parent.session.services.runtime_auth)),
Arc::clone(&parent.session.services.plugins_manager),
Some(parent.session.services.analytics_events_client.clone()),
)
} else {
let runtime_auth = inherited_runtime_auth.unwrap_or_default();
@@ -2634,7 +2654,35 @@ impl ThreadManagerState {
self.plugins_manager
.for_auth_context(Arc::clone(&auth_manager), Arc::clone(&runtime_auth)),
);
(runtime_auth, plugins)
let runtime_provider = config
.features
.enabled(Feature::RuntimeAgentInstances)
.then(|| (Arc::clone(&runtime_auth), config.runtime_auth_mode));
let analytics = self.analytics_events_client.as_ref().map(|client| {
let api_key_headers = if codex_model_provider::provider_uses_first_party_auth_path(
&config.model_provider,
) {
match config.model_provider.build_header_map() {
Ok(headers) => headers,
Err(error) => {
tracing::warn!(%error, "failed to resolve analytics resource selectors");
return codex_analytics::AnalyticsEventsClient::disabled();
}
}
} else {
Default::default()
};
client.for_auth_context(
Arc::clone(&auth_manager),
config.chatgpt_base_url.clone(),
runtime_provider,
api_key_headers,
)
});
if let Some(client) = &analytics {
plugins.set_analytics_events_client(client.clone());
}
(runtime_auth, plugins, analytics)
}
};
let mcp_manager = if Arc::ptr_eq(&plugins_manager, &self.plugins_manager) {
@@ -2708,7 +2756,7 @@ impl ThreadManagerState {
turn_extension_init,
client_mcp_extensions,
reserved_thread_id,
analytics_events_client: self.analytics_events_client.clone(),
analytics_events_client,
image_store: Arc::clone(&self.image_store),
thread_store: Arc::clone(&self.thread_store),
attestation_provider: self.attestation_provider.clone(),