OAuth Login Fails Behind Corporate Proxy with Custom CA Certificates

Open 💬 4 comments Opened Nov 18, 2025 by 3axap4eHko
💡 Likely answer: A maintainer (etraut-openai, contributor) responded on this thread — see the highlighted reply below.

What version of Codex is running?

0.58.0

What subscription do you have?

Bussiness

Which model were you using?

gpt-5.1-codex

What platform is your computer?

Darwin 23.6.0 arm64 arm

What issue are you seeing?

Summary

The Codex CLI fails to authenticate when running behind a corporate proxy that performs SSL/TLS inspection with custom CA certificates. The OAuth token exchange fails with the error:

Token exchange failed: error sending request for url (https://auth.openai.com/oauth/token)

Environment

  • OS: macOS (Darwin 23.6.0)
  • Codex CLI Version: 0.58.0

Problem Description

The Codex CLI OAuth login flow fails at the token exchange step when the user is behind a corporate proxy that uses custom SSL certificates for man-in-the-middle inspection (common in enterprise environments).

Authentication Flow

  1. User runs codex login
  2. Browser opens and user completes OAuth authorization ✅
  3. Browser redirects to http://localhost:1455/auth/callback?code=... ✅
  4. Local server receives the authorization code ✅
  5. Server attempts to exchange code for tokens via POST to https://auth.openai.com/oauth/token ❌
  6. Request fails because reqwest::Client doesn't trust the corporate CA certificate

Root Cause

In codex-rs/login/src/server.rs, the exchange_code_for_tokens (line 508) and obtain_api_key (line 698) functions use reqwest::Client::new(), which creates an HTTP client with only the system's default certificate roots.

let client = reqwest::Client::new();  // Does not trust custom CA certificates
let resp = client
    .post(format!("{issuer}/oauth/token"))
    .header("Content-Type", "application/x-www-form-urlencoded")
    .body(...)
    .send()
    .await
    .map_err(io::Error::other)?;  // Fails with SSL certificate verification error

When behind a corporate proxy with SSL inspection:

  • The connection to auth.openai.com is intercepted
  • The proxy presents a certificate signed by the corporate CA
  • reqwest doesn't trust this CA and rejects the connection
  • The token exchange fails with a generic "error sending request" message

Steps to Reproduce

  1. Configure corporate proxy with SSL inspection
  2. Export corporate CA certificates to PEM format
  3. Run codex login
  4. Complete OAuth flow in browser
  5. Observe error: Token exchange failed: error sending request for url (https://auth.openai.com/oauth/token)

Proposed Solution

Add support for custom CA certificates in the OAuth login flow, similar to how it's already implemented for OpenTelemetry exporters in codex-rs/otel/src/otel_provider.rs.

Implementation Approach

  1. Add CA certificate configuration to the login module:

``rust
pub struct LoginOptions {
// ... existing fields
pub ca_certificate: Option<PathBuf>,
}
``

  1. Create HTTP client with custom CA certificate (similar to otel_provider.rs:185-228):

```rust
fn build_http_client(ca_cert_path: Option<&PathBuf>) -> io::Result<reqwest::Client> {
let mut builder = reqwest::Client::builder();

if let Some(path) = ca_cert_path {
let pem = std::fs::read(path)?;
let certificate = reqwest::Certificate::from_pem(&pem)
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
builder = builder.add_root_certificate(certificate);
}

builder.build().map_err(io::Error::other)
}
```

  1. Update exchange_code_for_tokens and obtain_api_key to use the custom client:

``rust
let client = build_http_client(opts.ca_certificate.as_ref())?;
``

  1. Support environment variable (e.g., CODEX_CA_CERTIFICATE or reuse SSL_CERT_FILE)
  1. Support config file via ~/.codex/config.toml:

``toml
[login]
ca_certificate = "~/.certs/corporate-ca.pem"
``

Alternative Solutions

  1. Automatic detection: Check for SSL_CERT_FILE environment variable (used by many tools)
  2. System keychain: Use platform-specific APIs to load certificates from system trust stores
  3. Proxy detection: Auto-detect corporate proxy and prompt user to provide certificate

Related Code

  • Working TLS implementation: codex-rs/otel/src/otel_provider.rs:185-228 - Shows how to add custom CA certificates to reqwest::Client
  • Affected functions:
  • codex-rs/login/src/server.rs:494-536 - exchange_code_for_tokens()
  • codex-rs/login/src/server.rs:688-721 - obtain_api_key()
  • codex-rs/login/src/device_code_auth.rs:153 - Device code flow

Impact

This affects all Codex CLI users in corporate environments with:

  • SSL/TLS inspection proxies (Zscaler, Palo Alto Networks, etc.)
  • Custom internal CA certificates
  • Air-gapped environments with internal certificate authorities

Workarounds

Currently, users must either:

  1. Disable SSL verification (insecure): NODE_TLS_REJECT_UNAUTHORIZED=0 (doesn't help with Rust client)
  2. Bypass the proxy for OpenAI domains (may violate corporate policy)
  3. Cannot use Codex CLI (blocks adoption in enterprise environments)

References

What steps can reproduce the bug?

Try to login with codex on a machine that is behind corporate proxy with custom certificate

What is the expected behavior?

Exchange token successfully without 500 error

Additional information

_No response_

View original on GitHub ↗

4 Comments

etraut-openai contributor · 9 months ago

That's among the best (most detailed and helpful) bug reports we've received. Thank you!

ikunali · 7 months ago

This is still affecting latest codex version 0.88.0 @etraut-openai @tibo-openai

Hope this one gets prioritized, as I can easily use claude simply with NODE_TLS_REJECT_UNAUTHORIZED=0, whereas with codex I'm simply blocked just because of enterprise security MITM certs.

This will hugely help in enterprise adoption, as currently even codex login using device-auth isn't working, just because enterprise certs are force enabled over the network.

etraut-openai contributor · 7 months ago

@ikunali, the fix for this issue is currently blocked by an upstream dependency. See this PR thread if you're interested in the details.

liyoungc · 3 months ago

+1 — same blocker in a hospital LAN here (Sin-lau Hospital, Taiwan). I just filed #24167 with the runtime-side details: PR #20676 (the fix that closed/resolved this issue for login) is incomplete — chat path and WebSocket transport still hardcode rustls and reject our SHA1-RSA1024 hospital MITM CA, even with SSL_CERT_FILE / CODEX_CA_CERTIFICATE set.

"I can easily use claude simply with NODE_TLS_REJECT_UNAUTHORIZED=0, whereas with codex I'm simply blocked" — @ikunali

This is the exact same comparison we're seeing on 0.132 / 0.133 — claude-code (Node) sails through, codex (rustls) dies in chat after login. Healthcare can't change the corporate CA in any short timeframe; we genuinely need an opt-in --insecure / CODEX_INSECURE_TLS=1 / --tls-backend=native escape hatch.

Cross-linking #24167 in case anyone tracking this issue wants to add details from the runtime side.