Token exchange failed: token endpoint returned status 403 Forbidden means an authentication request was refused, but the error alone does not prove an OpenAI outage, a proxy problem, a region restriction, or stale credentials. First identify whether the failure happened at the localhost callback, the outbound token exchange, or the first authenticated Codex request. Before resetting anything, record codex --version, run codex login status, note where Codex is actually running, check the status page, and preserve the redacted response body. Do not delete ~/.codex, disable TLS verification, bypass a region restriction, or share a callback URL or token while the rejecting hop is still unknown.
| What you saw | Failing hop | First useful check |
|---|---|---|
| The browser never returned to Codex | localhost callback | Is the listener running in the same environment as the browser callback? |
| The browser approved sign-in, then Codex printed the exact token-exchange 403 | outbound token exchange | Inspect the response body, proxy/WAF path, CA trust, region/account policy, and execution environment |
| Login completed, but the first Codex request returned 403 | authenticated request | Check workspace entitlement, provider route, model access, and which credential source won |
The distinction matters because a localhost callback problem is not a token-endpoint rejection, and a later API 403 is not a failed exchange. Fix the hop you can prove. Stop changing network settings if the response body names an account, workspace, policy, or supported-country boundary.
“Verified 2026-07-12: the official OpenAI status page showed no known system-wide incident during this review. That is a useful first check, not proof that your specific network, account, workspace, or region route is healthy.
The seven-minute recovery sequence
Work in this order. It preserves evidence and makes each change reversible.
1. Record the client and current auth state
Run these commands in the same shell, container, WSL distribution, SSH host, or desktop environment where the failure occurred:
bashcodex --version codex login status
The current-run probe returned codex-cli 0.144.0-alpha.4; that is an observation, not a minimum supported version. Record your own output. A stale build is worth updating, but "update everything" is not a diagnosis.
If codex login status already reports the expected route, test one small authenticated request before starting a new login. You may be looking at an old terminal error rather than a current failure.
2. Check current service status
Open the OpenAI status page and note the timestamp. If an authentication or Codex incident is active, preserve your evidence and wait for the incident to clear before rewriting local configuration. If the page is green, continue; aggregate status cannot see a corporate proxy, local certificate chain, account policy, or workspace restriction.
3. Name the execution owner
Write down where the codex process actually runs:
- macOS, Windows, or Linux directly
- WSL, a container, or a remote SSH host
- an IDE terminal, CI runner, or managed developer environment
The browser may run on your laptop while Codex and its callback listener run elsewhere. If the browser approved sign-in but cannot reach the listener, you have a callback topology problem. If Codex received the callback and then reports that the token endpoint returned 403, the outbound exchange left the execution owner and was rejected later in the route.
4. Preserve the response without preserving secrets
Keep the exact status, timestamp with time zone, command, Codex version, and any short error code or request ID. Redact:
- authorization codes and access or refresh tokens
- the full callback URL and query string
- cookies, API keys, email addresses, organization IDs, and unrelated file paths
The response body can decide the branch. A named country/region policy, account restriction, workspace denial, or proxy-branded block page is more useful than the number 403 alone.
5. Retry once on a clean, known route
After recording evidence, make one controlled retry. Change only one owner: current Codex build, direct versus managed network, correct execution environment, trusted corporate CA, or clean credential state. Verify the same route afterward.
A fix passes only when login completes and this command reports the expected authentication method in the same environment:
bashcodex login status
Repeated blind login attempts can rotate codes and destroy the clean comparison you need.
How the Codex sign-in route actually fails

Treat Codex sign-in as five observable steps:
- Codex opens a browser authorization flow.
- The browser returns an authorization result to a local callback listener.
- Codex sends an outbound token request that trades the short-lived code for credentials.
- Codex stores credentials using its configured credential store.
- Codex makes its first authenticated request.
The exact token-exchange message belongs to step 3. This narrows the investigation, but it still leaves multiple rejecting layers: OpenAI policy or account controls, a corporate proxy/WAF, TLS interception and CA trust, the wrong runtime or route, or stale state that caused the exchange to use an invalid context.
OpenAI's Codex authentication documentation explains the supported sign-in routes and credential storage choices. Its environment-variable reference documents CODEX_CA_CERTIFICATE for a custom certificate authority bundle. Those official controls are safer than disabling certificate verification.
Branch matrix: proof, action, success, stop

| Branch | Evidence that points here | Bounded action | Success signal | Stop rule |
|---|---|---|---|---|
| proxy or WAF | proxy-branded HTML, corporate block ID, route works on a permitted direct network | ask the network owner to allow the required auth route; keep localhost callback traffic local | one clean login succeeds on the approved route | do not tunnel around organizational policy |
| corporate CA | certificate-chain errors, TLS inspection is documented, failure begins on managed network | set CODEX_CA_CERTIFICATE to the approved PEM bundle | exchange completes with verification still enabled | never use an insecure TLS flag |
| WSL, container, or remote host | browser and callback listener live in different network namespaces | run login where callback reachability is correct, or use an officially supported alternative auth flow | callback reaches the same Codex process | do not expose a callback listener publicly |
| country, region, or account policy | response body names unsupported_country_region_territory or an account restriction | verify the account and supported-country list; use support for mistakes | official route becomes eligible or support resolves the record | do not use a VPN or borrowed account to bypass the boundary |
| managed workspace | personal route works but SSO/workspace route is denied, or the body names workspace policy | ask the workspace administrator to confirm Codex access and identity policy | expected workspace auth succeeds | stop local proxy edits when policy is explicit |
| stale credential state | route and policy checks pass; logout/login changes the behavior | use codex logout, then perform one clean codex login | status reports the intended route and a request succeeds | do not delete the whole ~/.codex directory first |
Proxy handling: separate loopback from outbound traffic
A common mistake is to add every authentication hostname to NO_PROXY. The localhost callback and the outbound token exchange have opposite needs.
If your environment requires a proxy, loopback traffic should usually stay local:
bashexport NO_PROXY="localhost,127.0.0.1,::1"
But the outbound token request may still need the approved corporate proxy. Do not blindly bypass it. An OpenAI collaborator documented a Codex case where a proxy prevented access to localhost and recommended allowing the callback ports or using an alternative authentication path. That supports a topology check; it does not prove every 403 is caused by a proxy.
Check proxy variables without publishing their credentials:
bashenv | grep -iE '^(HTTP|HTTPS|ALL|NO)_PROXY='
If the value contains usernames, passwords, or internal hosts, redact it before sharing.
Corporate TLS inspection: trust the approved CA
When a company legitimately intercepts TLS, obtain the approved PEM certificate bundle from the network or security team and point Codex to it:
bashexport CODEX_CA_CERTIFICATE="/path/to/company-ca-bundle.pem" codex login
OpenAI's current Codex environment reference also lists standard certificate variables as fallback mechanisms, but CODEX_CA_CERTIFICATE is the Codex-specific control to prefer. A certificate failure and an HTTP 403 are different signals; use this branch when chain or interception evidence exists, not as a universal fix.
Region, account, and workspace boundaries
If the response explicitly names a country or territory, compare the account's real location and access route with OpenAI's current supported-country list. A supported-country page is volatile, so check it on the day you troubleshoot. If the account should be eligible, contact support with the redacted response and timestamp.
For a managed Business, Enterprise, Edu, or SSO workspace, ask the administrator whether Codex is enabled for the expected identity and whether the organization requires a specific login route. An administrator policy cannot be repaired by deleting a local cache.
Reset only the credential layer you mean to reset
The reversible reset is:
bashcodex logout codex login
Do not start with rm -rf ~/.codex. That directory can include configuration, state, logs, and other context you may need. A community workaround that deletes the entire directory can appear to help while erasing the evidence that distinguishes credentials from proxy, policy, or runtime ownership.
If you need to inspect where Codex keeps state and configuration before changing anything, see the Codex config.toml guide. Treat credential files as secrets: do not copy another person's auth.json, paste it into a ticket, sync it through chat, or commit it.
Alternative authentication routes and their tradeoffs
The CLI build checked on 2026-07-12 exposed these login options:
bashcodex login --device-auth codex login --with-api-key codex login --with-access-token
Use only a route authorized for your environment.
- Device authentication can help when browser-to-localhost topology is the blocker. It is not a way around an account or country policy.
- API-key login is a developer-billing route. It can have different feature, billing, and workspace behavior from ChatGPT subscription login. Read Codex API key vs subscription before treating it as equivalent.
- Access-token login is appropriate only for a trusted, documented automation or enterprise flow. Do not paste an access token into shell history or a public issue.
If you use an API key, pipe it without printing it:
bashprintenv OPENAI_API_KEY | codex login --with-api-key
Changing authentication routes is a product decision, not proof that the original route was fixed. It can also change which Codex usage limits and billing contract apply.
What to send support or your administrator

Escalate immediately when the body identifies account, workspace, country/region, or policy rejection. Otherwise, escalate after one clean retry on a current build and an approved route.
Send a compact evidence pack:
- exact error text and redacted response body
- timestamp with time zone
codex --versionand the intended authentication mode- OS plus execution owner: host, WSL, container, remote, IDE, or CI
- whether the browser callback returned successfully
- whether a corporate proxy, WAF, VPN, or TLS inspection is present
- request ID, support thread ID, or Codex
/feedbackthread ID when available - one controlled change you tried and its result
Never attach the callback URL, authorization code, token, API key, cookie, complete auth.json, or unredacted proxy URL. In a public GitHub issue, keep the evidence even narrower.
FAQ
Does a token exchange 403 mean OpenAI is down?
No. It proves a request was refused at the exchange route. Check the current status page, but also inspect the response body, network path, account/workspace policy, region eligibility, and execution environment.
Why did the browser say login succeeded while Codex failed?
Browser authorization and token exchange are separate hops. The browser can approve the user while the outbound code-for-token request is later rejected by a proxy, policy layer, account rule, or stale context.
Should I add OpenAI domains to NO_PROXY?
Not blindly. Keep loopback names such as localhost, 127.0.0.1, and ::1 local when appropriate. The outbound token endpoint may be required to traverse your approved proxy. Confirm the corporate routing policy before changing it.
Should I delete ~/.codex?
Not as a first action. Preserve evidence, use codex logout, and retry one clean login. Inspect configuration and state deliberately if the credential-only reset does not help.
Can I switch to an API key to get around the 403?
You can use API-key authentication when it is supported and fits your task, but it changes billing and feature context. It does not override account, workspace, or supported-country policy and does not prove the ChatGPT login route is repaired.
When should I stop troubleshooting locally?
Stop immediately if the response names a policy, account, workspace, or country/region denial. Otherwise stop after one clean current-build retry on an approved route fails with the same evidence. At that point, send the redacted evidence pack to OpenAI Support, your workspace administrator, or the network owner who controls the rejecting layer.
The shortest safe rule is: identify the hop, preserve the body, change one owner, verify the same route, and stop at policy boundaries.
