Add trusted enterprise MCP auth configuration (#44832)

## Why

Enterprise MCP authorization must remain controlled by host, user, or managed configuration. Project settings and plugin declarations must not redirect enterprise credentials or downgrade the selected authentication mode.

## What changed

- Add `auth = "ema_auth"`, shared `mcp_enterprise_managed_auth` IdP configuration, and per-plugin enterprise registration settings.
- Require enterprise registrations to come from one non-project configuration layer, preserve managed IdP precedence, and reject project overrides that change authorization or re-enable disabled enterprise servers.
- Add the disabled-by-default `use_xaa` feature flag and require non-project opt-in or a managed requirement.
- Reject plugin declarations that select `ema_auth`. Keep EMA connections unsupported and block ordinary MCP OAuth login and credential fallback for this mode.
- Extend the configuration schema and serialization for the new settings.

## Testing

Add coverage for IdP precedence, incomplete registrations, alternate credential validation, project-only opt-in, plugin self-declaration rejection, configuration round-tripping, and trusted-project attempts to downgrade enterprise auth to OAuth or ChatGPT auth.

GitOrigin-RevId: f193bdfda74208c98e496a23bf2916955b131a1c
This commit is contained in:
Nick Steele authored and copyberry committed 2026-09-11 14:25:56 +00:00
1 parent 7a6f469dcf
commit 654b0a77d0
28 files changed
+872 -31

No files matched your search

+105 -3
View File
@@ -1073,6 +1073,9 @@
"use_linux_sandbox_bwrap": {
"type": "boolean"
},
"use_xaa": {
"type": "boolean"
},
"view_image": {
"type": "boolean"
},
@@ -2073,8 +2076,25 @@
},
"type": "object"
},
"McpEnterpriseManagedAuthConfig": {
"additionalProperties": false,
"properties": {
"idp": {
"allOf": [
{
"$ref": "#/definitions/McpServerIdpOAuthConfig"
}
],
"description": "Shared enterprise authorization, independent of Codex account credentials."
}
},
"required": [
"idp"
],
"type": "object"
},
"McpServerAuth": {
"description": "Authentication flow Codex attempts after resolving an HTTP MCP server's configured bearer token and authorization headers, which always take precedence. ChatGPT authentication falls back to stored OAuth credentials when its session provider is unavailable; both modes ultimately fall back to an unauthenticated connection.",
"description": "Authentication flow for an HTTP MCP server. Explicit credentials take precedence for OAuth and ChatGPT; EMA rejects alternate credentials and fallback.",
"oneOf": [
{
"description": "Use stored MCP OAuth credentials when available. Starting an OAuth login is a separate operation.",
@@ -2089,6 +2109,13 @@
"chatgpt"
],
"type": "string"
},
{
"description": "Exchange an enterprise IdP refresh token for resource-specific authorization. Alternate credentials and ordinary OAuth fallback are not permitted.",
"enum": [
"ema_auth"
],
"type": "string"
}
]
},
@@ -2114,10 +2141,32 @@
}
]
},
"McpServerIdpOAuthConfig": {
"additionalProperties": false,
"properties": {
"client_id": {
"description": "Public OAuth client registered with that enterprise IdP.",
"type": "string"
},
"issuer": {
"description": "Issuer used for enterprise OAuth discovery and identity validation.",
"type": "string"
}
},
"required": [
"client_id",
"issuer"
],
"type": "object"
},
"McpServerOAuthConfig": {
"additionalProperties": false,
"description": "OAuth client settings used when Codex launches an MCP OAuth flow.",
"description": "Client settings for MCP OAuth login or enterprise token exchange.",
"properties": {
"authorization_server_issuer": {
"description": "Expected resource authorization server issuer for EMA token exchange.",
"type": "string"
},
"callback_port": {
"description": "Fixed callback port that takes precedence over Codex's global OAuth callback port.",
"format": "uint16",
@@ -3167,7 +3216,7 @@
},
"PluginMcpServerConfig": {
"additionalProperties": false,
"description": "Policy settings for a plugin-provided MCP server.\n\nThis intentionally excludes transport settings: plugin manifests own how the MCP server is launched, while user config owns enablement and tool policy.",
"description": "Policy settings for a plugin-provided MCP server.\n\nThis intentionally excludes transport settings: plugin manifests own how the MCP server is launched, while host config owns enablement, auth, and tool policy.",
"properties": {
"default_tools_approval_mode": {
"allOf": [
@@ -3184,6 +3233,14 @@
},
"type": "array"
},
"ema_auth": {
"allOf": [
{
"$ref": "#/definitions/PluginMcpServerEmaAuthConfig"
}
],
"description": "Host-configured EMA registration; the plugin still owns its endpoint."
},
"enabled": {
"default": true,
"description": "When `false`, Codex skips initializing this plugin MCP server.",
@@ -3206,6 +3263,39 @@
},
"type": "object"
},
"PluginMcpServerEmaAuthConfig": {
"additionalProperties": false,
"description": "Resource registration applied through an existing per-plugin policy overlay. The enterprise IdP is selected separately by trusted host configuration.",
"properties": {
"authorization_server_issuer": {
"type": "string"
},
"client_id": {
"type": "string"
},
"resource": {
"type": "string"
},
"scopes": {
"default": [],
"items": {
"type": "string"
},
"type": "array"
},
"url": {
"description": "Exact plugin endpoint approved by the host; never overrides the declaration.",
"type": "string"
}
},
"required": [
"authorization_server_issuer",
"client_id",
"resource",
"url"
],
"type": "object"
},
"ProfileTui": {
"additionalProperties": false,
"description": "TUI settings supported inside a named profile.",
@@ -6598,6 +6688,9 @@
"use_linux_sandbox_bwrap": {
"type": "boolean"
},
"use_xaa": {
"type": "boolean"
},
"view_image": {
"type": "boolean"
},
@@ -6740,6 +6833,15 @@
"description": "User-level marketplace entries keyed by marketplace name.",
"type": "object"
},
"mcp_enterprise_managed_auth": {
"allOf": [
{
"$ref": "#/definitions/McpEnterpriseManagedAuthConfig"
}
],
"default": null,
"description": "Trusted enterprise IdP shared by EMA-enabled MCP servers and plugins."
},
"mcp_oauth_callback_port": {
"description": "Optional fixed port for the local HTTP callback server used during MCP OAuth login. When unset, Codex will bind to an ephemeral port chosen by the OS.",
"format": "uint16",