Summary
codex mcp login <server> fails instantly with Error: No authorization support detected
on macOS (arm64) against a fully spec-compliant OAuth 2.0 authorization server.
The same codex version completes the entire flow on Linux against the same server
(discovery → dynamic client registration → browser → token). Other MCP clients
(Claude Code, mcp-remote) complete OAuth against this server without issues —
including mcp-remote running on the same Mac, which rules out the machine's
network/TLS stack and the server itself.
A second, independent defect (RFC 9207 iss dropped when relaying the OAuth callback)
was found while debugging; see the last section. Happy to split it into its own issue.
Environment
- codex-cli 0.144.6 (pins rmcp 1.8.0 per
codex-rs/Cargo.lock of tag rust-v0.144.6)
- macOS: 26.5.2, BuildVersion 25F84;
uname -m = arm64 (Mac mini)
- Install: official binary at
~/.local/bin/codex; also reproduced with the pristine
release tarball codex-aarch64-apple-darwin.tar.gz from the rust-v0.144.6 GitHub
release, executed directly
- No proxies:
env | grep -i proxy is empty; scutil --proxy shows only the default
ExceptionsList (*.local, 169.254/16), no HTTP/HTTPS/SOCKS/PAC
- Reproduced with a fresh
CODEX_HOME (empty directory), so user config is not involved
RUST_LOG=debug codex mcp login <server> prints nothing beyond the error itself
Repro steps (macOS)
mkdir -p ~/codex-test && cd ~/codex-test
curl -LO https://github.com/openai/codex/releases/download/rust-v0.144.6/codex-aarch64-apple-darwin.tar.gz
tar xzf codex-aarch64-apple-darwin.tar.gz
mkdir home && export CODEX_HOME=~/codex-test/home
./codex-aarch64-apple-darwin mcp add sparrow --url https://mcp.example.com/mcp
# → Added global MCP server 'sparrow'.
# → Detected OAuth support. Starting OAuth flow…
# → Error: No authorization support detected
./codex-aarch64-apple-darwin mcp login sparrow
# → Error: No authorization support detected
(Hostname sanitized throughout: mcp.example.com = a self-hosted MCP server behind
nginx with a valid Let's Encrypt certificate, reachable over the public internet.)
Server capabilities
Self-hosted MCP server (Streamable HTTP) whose app is its own OAuth 2.0 authorization
server (OpenIddict 7.5):
401 on /mcp with
WWW-Authenticate: Bearer resource_metadata="https://mcp.example.com/.well-known/oauth-protected-resource"
- RFC 9728 protected resource metadata at the root path and the path-suffixed variant
(/.well-known/oauth-protected-resource/mcp)
- RFC 8414 AS metadata at
/.well-known/oauth-authorization-server (root and
path-suffixed), plus /.well-known/openid-configuration
- RFC 7591 dynamic client registration (
registration_endpoint advertised; returns 201
with a public PKCE client, token_endpoint_auth_method=none)
token_endpoint_auth_methods_supported includes "none"
authorization_servers[0] matches the AS issuer byte-for-byte (trailing slash included)
- Authorization Code + PKCE (S256);
response_types_supported: ["code"]
What the server sees during a failing macOS codex mcp login (nginx access log)
CLIENT_IP - - [20/Jul/2026:18:30:56 +0000] "GET /mcp HTTP/1.1" 401 0 "-" "-"
CLIENT_IP - - [20/Jul/2026:18:30:56 +0000] "GET /.well-known/oauth-protected-resource HTTP/1.1" 200 218 "-" "-"
CLIENT_IP - - [20/Jul/2026:18:30:56 +0000] "GET /.well-known/oauth-authorization-server HTTP/1.1" 200 1653 "-" "-"
All three requests succeed — then nothing. No fallback attempt to
/.well-known/openid-configuration, no POST to the registration endpoint. The CLI
prints Error: No authorization support detected immediately.
This should be impossible if the 200 AS-metadata response was actually processed:
rmcp 1.8.0's discover_metadata() returns NoAuthorizationSupport only after all
discovery candidates fail, and a successful parse of that document would have continued
to DCR (as it does on Linux, below). This suggests the login path's HTTP client fails
client-side on macOS, separately from the requests above.
Same binary version on Linux (x86_64) — full success
CLIENT_IP - - [20/Jul/2026:18:02:01 +0000] "POST /oauth/register HTTP/1.1" 201 261 "-" "-"
CLIENT_IP - - [20/Jul/2026:18:02:01 +0000] "GET /oauth/authorize?response_type=code&client_id=…&code_challenge=…&code_challenge_method=S256&redirect_uri=http%3A%2F%2F127.0.0.1%3A33721%2Fcallback%2F…&scope=openid+offline_access+mcp&resource=https%3A%2F%2Fmcp.example.com%2Fmcp HTTP/2.0" 302 0
codex mcp login output on Linux (after the RFC 9207 server-side workaround described
below): Successfully logged in to MCP server 'sparrow'. — codex mcp list shows
Status enabled / Auth OAuth.
mcp-remote from the SAME Mac — full success
CLIENT_IP - - [20/Jul/2026:18:58:26 +0000] "GET /oauth/authorize?…" 302 … "node"
CLIENT_IP - - [20/Jul/2026:18:58:26 +0000] "GET /.well-known/oauth-protected-resource/mcp HTTP/1.1" 200 218 "-" "node"
CLIENT_IP - - [20/Jul/2026:18:58:26 +0000] "POST /oauth/token HTTP/1.1" 200 4575 "-" "node"
CLIENT_IP - - [20/Jul/2026:18:58:26 +0000] "POST /mcp HTTP/1.1" 200 77092 "-" "node" ← tools/list
Same machine, same network, same server: the stdio bridge (codex mcp add sparrow -- npx -y mcp-remote https://mcp.example.com/mcp) completes OAuth and lists tools. This is
our current workaround.
Live metadata documents (sanitized)
GET /.well-known/oauth-protected-resource → 200:
{"resource":"https://mcp.example.com/mcp","authorization_servers":["https://mcp.example.com/"],"scopes_supported":["mcp","offline_access"],"bearer_methods_supported":["header"]}
GET /.well-known/oauth-authorization-server → 200 (identical at
/.well-known/openid-configuration and both path-suffixed variants):
{
"issuer": "https://mcp.example.com/",
"authorization_endpoint": "https://mcp.example.com/oauth/authorize",
"token_endpoint": "https://mcp.example.com/oauth/token",
"revocation_endpoint": "https://mcp.example.com/oauth/revoke",
"jwks_uri": "https://mcp.example.com/.well-known/jwks",
"grant_types_supported": ["authorization_code", "refresh_token"],
"response_types_supported": ["code"],
"response_modes_supported": ["query", "form_post", "fragment"],
"scopes_supported": ["openid", "offline_access", "mcp"],
"claims_supported": ["aud", "exp", "iat", "iss", "sub"],
"id_token_signing_alg_values_supported": ["RS256"],
"code_challenge_methods_supported": ["plain", "S256"],
"subject_types_supported": ["public"],
"prompt_values_supported": ["consent", "login", "none", "select_account"],
"token_endpoint_auth_methods_supported": ["none", "client_secret_basic", "client_secret_post", "private_key_jwt"],
"revocation_endpoint_auth_methods_supported": ["client_secret_post", "private_key_jwt", "client_secret_basic"],
"require_pushed_authorization_requests": false,
"tls_client_certificate_bound_access_tokens": false,
"registration_endpoint": "https://mcp.example.com/oauth/register",
"claims_parameter_supported": false,
"request_parameter_supported": false,
"request_uri_parameter_supported": false,
"authorization_response_iss_parameter_supported": false,
"authorization_response_iss_parameter_supported_NOTE": "false is a WORKAROUND for the second bug below; the server actually sends iss. It was true when that bug reproduced."
}
(The _NOTE key is annotation for this issue, not part of the live document.)
Second defect: RFC 9207 iss is dropped when relaying the OAuth callback
Found while debugging on Linux, where the flow gets further. With
authorization_response_iss_parameter_supported: true advertised (the honest value),
codex mcp login on Linux failed at the callback stage:
Error: failed to handle OAuth callback
Caused by:
Authorization server response missing required issuer: expected https://mcp.example.com/
Evidence the server sends iss correctly — raw callback captured with a local listener
(DCR probe client, browser completed the redirect):
GET /cb?code=…&state=…&iss=https%3A%2F%2Fmcp.example.com%2F HTTP/1.1
Byte-exact match with the advertised issuer. Cause, from the codex source
(codex-rs/rmcp-client/src/perform_oauth_login.rs): the local callback server extracts
only code and state (OauthCallbackResult { code, state }) and calls
oauth_state.handle_callback(&code, &csrf_state) — the variant without issuer.
rmcp 1.8.0 (validate_authorization_response_issuer) then requires iss because the
AS metadata advertises support → guaranteed failure against any server that honestly
advertises RFC 9207. Codex discards the very parameter rmcp then demands.
Suggested fix: extract iss from the callback query and use
handle_callback_with_issuer / handle_callback_url.
Current server-side workaround (required for codex to work at all): advertise
authorization_response_iss_parameter_supported: false while still sending iss.
Expected behavior
- macOS: the OAuth flow proceeds as it does on Linux — or the error names the actual
failing step instead of No authorization support detected after three successful
discovery responses.
- The callback relay preserves
iss so servers can honestly advertise RFC 9207.
Summary
codex mcp login <server>fails instantly withError: No authorization support detectedon macOS (arm64) against a fully spec-compliant OAuth 2.0 authorization server.
The same codex version completes the entire flow on Linux against the same server
(discovery → dynamic client registration → browser → token). Other MCP clients
(Claude Code,
mcp-remote) complete OAuth against this server without issues —including
mcp-remoterunning on the same Mac, which rules out the machine'snetwork/TLS stack and the server itself.
A second, independent defect (RFC 9207
issdropped when relaying the OAuth callback)was found while debugging; see the last section. Happy to split it into its own issue.
Environment
codex-rs/Cargo.lockof tagrust-v0.144.6)uname -m=arm64(Mac mini)~/.local/bin/codex; also reproduced with the pristinerelease tarball
codex-aarch64-apple-darwin.tar.gzfrom therust-v0.144.6GitHubrelease, executed directly
env | grep -i proxyis empty;scutil --proxyshows only the defaultExceptionsList(*.local,169.254/16), no HTTP/HTTPS/SOCKS/PACCODEX_HOME(empty directory), so user config is not involvedRUST_LOG=debug codex mcp login <server>prints nothing beyond the error itselfRepro steps (macOS)
(Hostname sanitized throughout:
mcp.example.com= a self-hosted MCP server behindnginx with a valid Let's Encrypt certificate, reachable over the public internet.)
Server capabilities
Self-hosted MCP server (Streamable HTTP) whose app is its own OAuth 2.0 authorization
server (OpenIddict 7.5):
401on/mcpwithWWW-Authenticate: Bearer resource_metadata="https://mcp.example.com/.well-known/oauth-protected-resource"(
/.well-known/oauth-protected-resource/mcp)/.well-known/oauth-authorization-server(root andpath-suffixed), plus
/.well-known/openid-configurationregistration_endpointadvertised; returns 201with a public PKCE client,
token_endpoint_auth_method=none)token_endpoint_auth_methods_supportedincludes"none"authorization_servers[0]matches the ASissuerbyte-for-byte (trailing slash included)response_types_supported: ["code"]What the server sees during a failing macOS
codex mcp login(nginx access log)All three requests succeed — then nothing. No fallback attempt to
/.well-known/openid-configuration, noPOSTto the registration endpoint. The CLIprints
Error: No authorization support detectedimmediately.This should be impossible if the 200 AS-metadata response was actually processed:
rmcp 1.8.0's
discover_metadata()returnsNoAuthorizationSupportonly after alldiscovery candidates fail, and a successful parse of that document would have continued
to DCR (as it does on Linux, below). This suggests the login path's HTTP client fails
client-side on macOS, separately from the requests above.
Same binary version on Linux (x86_64) — full success
codex mcp loginoutput on Linux (after the RFC 9207 server-side workaround describedbelow):
Successfully logged in to MCP server 'sparrow'.—codex mcp listshowsStatus enabled / Auth OAuth.mcp-remotefrom the SAME Mac — full successSame machine, same network, same server: the stdio bridge (
codex mcp add sparrow -- npx -y mcp-remote https://mcp.example.com/mcp) completes OAuth and lists tools. This isour current workaround.
Live metadata documents (sanitized)
GET /.well-known/oauth-protected-resource→ 200:{"resource":"https://mcp.example.com/mcp","authorization_servers":["https://mcp.example.com/"],"scopes_supported":["mcp","offline_access"],"bearer_methods_supported":["header"]}GET /.well-known/oauth-authorization-server→ 200 (identical at/.well-known/openid-configurationand both path-suffixed variants):{ "issuer": "https://mcp.example.com/", "authorization_endpoint": "https://mcp.example.com/oauth/authorize", "token_endpoint": "https://mcp.example.com/oauth/token", "revocation_endpoint": "https://mcp.example.com/oauth/revoke", "jwks_uri": "https://mcp.example.com/.well-known/jwks", "grant_types_supported": ["authorization_code", "refresh_token"], "response_types_supported": ["code"], "response_modes_supported": ["query", "form_post", "fragment"], "scopes_supported": ["openid", "offline_access", "mcp"], "claims_supported": ["aud", "exp", "iat", "iss", "sub"], "id_token_signing_alg_values_supported": ["RS256"], "code_challenge_methods_supported": ["plain", "S256"], "subject_types_supported": ["public"], "prompt_values_supported": ["consent", "login", "none", "select_account"], "token_endpoint_auth_methods_supported": ["none", "client_secret_basic", "client_secret_post", "private_key_jwt"], "revocation_endpoint_auth_methods_supported": ["client_secret_post", "private_key_jwt", "client_secret_basic"], "require_pushed_authorization_requests": false, "tls_client_certificate_bound_access_tokens": false, "registration_endpoint": "https://mcp.example.com/oauth/register", "claims_parameter_supported": false, "request_parameter_supported": false, "request_uri_parameter_supported": false, "authorization_response_iss_parameter_supported": false, "authorization_response_iss_parameter_supported_NOTE": "false is a WORKAROUND for the second bug below; the server actually sends iss. It was true when that bug reproduced." }(The
_NOTEkey is annotation for this issue, not part of the live document.)Second defect: RFC 9207
issis dropped when relaying the OAuth callbackFound while debugging on Linux, where the flow gets further. With
authorization_response_iss_parameter_supported: trueadvertised (the honest value),codex mcp loginon Linux failed at the callback stage:Evidence the server sends
isscorrectly — raw callback captured with a local listener(DCR probe client, browser completed the redirect):
Byte-exact match with the advertised issuer. Cause, from the codex source
(
codex-rs/rmcp-client/src/perform_oauth_login.rs): the local callback server extractsonly
codeandstate(OauthCallbackResult { code, state }) and callsoauth_state.handle_callback(&code, &csrf_state)— the variant without issuer.rmcp 1.8.0 (
validate_authorization_response_issuer) then requiresissbecause theAS metadata advertises support → guaranteed failure against any server that honestly
advertises RFC 9207. Codex discards the very parameter rmcp then demands.
Suggested fix: extract
issfrom the callback query and usehandle_callback_with_issuer/handle_callback_url.Current server-side workaround (required for codex to work at all): advertise
authorization_response_iss_parameter_supported: falsewhile still sendingiss.Expected behavior
failing step instead of
No authorization support detectedafter three successfuldiscovery responses.
issso servers can honestly advertise RFC 9207.