codex icon indicating copy to clipboard operation
codex copied to clipboard

fix: add custom CA certificate support for login flows

Open 3axap4eHko opened this issue 1 month ago • 26 comments

What

Adds support for custom CA certificates in OAuth login flows to fix authentication failures behind corporate proxies with SSL/TLS inspection.

Why

The Codex CLI fails to authenticate when running behind corporate proxies that perform SSL/TLS inspection with custom CA certificates. The OAuth token exchange fails because reqwest::Client::new() only trusts system default certificate roots, causing it to reject connections intercepted by corporate proxies presenting certificates signed by custom CAs.

This affects all Codex CLI users in enterprise environments with:

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

Fixes #6849

How

Implementation:

  • Added build_login_http_client() function that creates an HTTP client with custom CA certificate support
  • Reads CA certificate path from environment variables (priority order):
    1. CODEX_CA_CERTIFICATE (primary)
    2. SSL_CERT_FILE (fallback, standard across many tools)
  • Updated all three authentication flows to use the custom client:
    • exchange_code_for_tokens() (OAuth code exchange)
    • obtain_api_key() (API key exchange)
    • run_device_code_login() (device code flow)
  • Follows the same pattern as existing otel_provider.rs implementation

Testing:

  • Added comprehensive test coverage with 3 new tests:
    • Certificate loading via CODEX_CA_CERTIFICATE env var
    • Certificate loading via SSL_CERT_FILE fallback
    • Invalid certificate rejection with proper error handling
  • All existing tests continue to pass
  • Added serial_test dependency to safely test env var manipulation

Usage:

export CODEX_CA_CERTIFICATE=/path/to/corporate-ca.pem
codex login

or using the standard env var:

export SSL_CERT_FILE=/path/to/corporate-ca.pem
codex login

Testing:

  • ✅ All tests pass (cargo test)
  • ✅ No clippy warnings (cargo clippy --tests -- -D warnings)
  • ✅ Code formatted (cargo fmt --check)
  • ✅ Tested with both environment variables
  • ✅ Invalid certificate properly rejected with clear error message

3axap4eHko avatar Nov 19 '25 01:11 3axap4eHko

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

github-actions[bot] avatar Nov 19 '25 01:11 github-actions[bot]

I have read the CLA Document and I hereby sign the CLA

3axap4eHko avatar Nov 19 '25 01:11 3axap4eHko

@codex review

etraut-openai avatar Nov 19 '25 04:11 etraut-openai

@codex review

3axap4eHko avatar Nov 20 '25 00:11 3axap4eHko

@codex review

etraut-openai avatar Nov 20 '25 22:11 etraut-openai

Codex Review: Didn't find any major issues. Breezy!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@3axap4eHko, thanks for the contribution! It looks like there are some minor code format issues. Please fix those when you have time.

etraut-openai avatar Nov 20 '25 22:11 etraut-openai

@3axap4eHko, the PR is looking good. We'll need to document the new environment variables. Ideally, this should be part of the same PR. Do you want to take a shot at adding the documentation?

etraut-openai avatar Nov 21 '25 19:11 etraut-openai

I'm assuming that your environment sets some sort of CA root authority that your general tools (browser etc.) properly check, so you don't tend to get errors in non-cli tooling. Is this something that we could generally load from the environment in the same way without having to manually configure this with environment variables? I.e. perhaps configuring the tooling to load from the OS Cert store where this is setup. There's probably a crate that sets this up automatically if that's the case. I'm not sure whether this is relevant to the use cases here, so please forgive the naive question.

joshka-oai avatar Nov 21 '25 20:11 joshka-oai

I'm assuming that your environment sets some sort of CA root authority that your general tools (browser etc.) properly check, so you don't tend to get errors in non-cli tooling. Is this something that we could generally load from the environment in the same way without having to manually configure this with environment variables? I.e. perhaps configuring the tooling to load from the OS Cert store where this is setup. There's probably a crate that sets this up automatically if that's the case. I'm not sure whether this is relevant to the use cases here, so please forgive the naive question.

Totally fair question. Out of the box, reqwest already trusts the platform store (via either system OpenSSL/Schannel/Security‑Framework on the blocking TLS stack or rustls-native-certs when using the rustls backend). That’s the reason browsers and “normal” CLI calls don’t need extra configuration. The new code only kicks in when you explicitly point CODEX_CA_CERTIFICATE or SSL_CERT_FILE at a custom bundle, because corporate proxies often publish their own root chain that isn’t in the OS store.

So, for users whose proxy installs its cert into the regular Windows/macOS/Linux trust store, nothing special is required—the default client still works. The env knob is just for the cases where IT hands you a standalone PEM bundle instead of touching the OS store. In that scenario you still need manual configuration somewhere, either by importing the PEM into the OS trust store (which is painful to automate across platforms) or by telling the app exactly which file to add. The helper we added is that second option.

If we ever run into a platform where the OS store is available but reqwest/rustls can’t discover it, the fix would likely be as simple as enabling the rustls-native-certs crate (or the native-tls backend) for that target. But so far there hasn’t been a report that the default trust roots are being ignored; every bug we’ve seen came from proxy-issued certs that the OS store rightfully doesn’t trust.

3axap4eHko avatar Nov 21 '25 23:11 3axap4eHko

@3axap4eHko, I wanted to give you an update on this PR. Since it involves security-sensitive code, we have pulled in some security experts outside of the codex team to provide a more thorough code review. This is a holiday week in the U.S. (Thanksgiving), so many OpenAI employees are out of the office. That means we probably won't make any further progress on this until next week.

etraut-openai avatar Nov 26 '25 01:11 etraut-openai

After chatting about this with our internal security, we'd prefer to have the settings for this added to the config.toml file rather than as an environment variable. If you're concerned that you need single call setups (where you don't want to set this at the entire machine level) codex has a --config flag that can generally be used to pass config key/values like this. We don't need to add a specific command line flag for this. Let's call this setting login_ca_certificate.

Let's use rustls-pki-types to open / parse the pem files rather thank hand coded.

Happy to continue the implementation on this with codex, or let you complete it. The things I'd generally want to make sure are covered here:

  • the rationale that covers why this setting is necessary is covered in the code as a doc comment on the code, and in the configuration docs (https://github.com/openai/codex/blob/main/docs/config.md#authentication-and-authorization)
  • tests (the ones you have look good - modify to be config based instead of environment variable based)

joshka-oai avatar Nov 26 '25 01:11 joshka-oai

After chatting about this with our internal security, we'd prefer to have the settings for this added to the config.toml file rather than as an environment variable. If you're concerned that you need single call setups (where you don't want to set this at the entire machine level) codex has a --config flag that can generally be used to pass config key/values like this. We don't need to add a specific command line flag for this. Let's call this setting login_ca_certificate.

Let's use rustls-pki-types to open / parse the pem files rather thank hand coded.

Happy to continue the implementation on this with codex, or let you complete it. The things I'd generally want to make sure are covered here:

  • the rationale that covers why this setting is necessary is covered in the code as a doc comment on the code, and in the configuration docs (https://github.com/openai/codex/blob/main/docs/config.md#authentication-and-authorization)
  • tests (the ones you have look good - modify to be config based instead of environment variable based)

@joshka-oai One thing I want to push back on in the "after chatting with internal security" part: environment-based CA configuration is a very common pattern on Unix. SSL_CERT_FILE is the standard OpenSSL convention and is used by tools like curl, git, Python requests, etc. It’s not inherently less secure than putting the same path in config.toml; both are just configuration channels, but it allows to avoid micromanage every cli tool.

If the Codex policy is "all TLS-related overrides must live in config.toml and we intentionally ignore SSL_CERT_FILE", that’s a valid product/design decision. But it’s different from saying that using SSL_CERT_FILE is a security concern. I’d prefer we frame this explicitly as "Codex chooses config-over-env for CA overrides" (and document that) rather than implying the standard env-based mechanism is problematic.

3axap4eHko avatar Dec 01 '25 12:12 3axap4eHko

I'm in general agreement with you, but I'm not sure if there's things I don't know about this yet. I'll follow up with our security folk and will get back to you on this shortly.

joshka-oai avatar Dec 01 '25 18:12 joshka-oai

I clarified with our Security team. We're fine with using environment variables on this. I misread a recommendation in a message.

The main part of getting this over the line is testing this correctly in a way that doesn't cause other usages of this code path to be impacted. Leaving the ball with you for now to take a look, but feel free to ask more questions or kick it back to us if you're not sure of the right direction on this.

joshka-oai avatar Dec 01 '25 21:12 joshka-oai