openai / openai/codex

[WSL2][Auth] Device-code final token exchange queries 127.0.0.1:53 instead of configured DNS resolver

Open
#42,528 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

auth bug CLI connectivity windows-os
Dominant language
Rust
Stars
125k
Forks
19.4k
PR merge metrics
PR metrics pending

Description

What version of Codex are you using?

Reproduced on:

  • codex-cli 0.152.1
  • codex-cli 0.153.0
Platform
  • Linux x86_64 under WSL2
  • /etc/resolv.conf is configured with the WSL DNS resolver (10.255.255.254 in this reproduction)
  • No DNS service is listening on 127.0.0.1:53
Summary

codex login --device-auth successfully obtains a device code, successfully polls the device-auth endpoint, and the browser approval succeeds. The failure occurs only at the final OAuth token exchange.

A packet-level capture of DNS traffic during the full flow shows that the working polling path and the failing final exchange use different DNS servers:

polling path:
auth.openai.com -> 10.255.255.254:53 -> response received

post-approval final exchange:
auth.openai.com -> 127.0.0.1:53 -> no response
retransmit -> 127.0.0.1:53 -> no response
final token exchange fails

The final error is:

oauth token exchange transport failure is_timeout=false is_connect=true is_request=true
error=error sending request for url (https://auth.openai.com/oauth/token)

No TCP connection to an OpenAI endpoint is attempted after the failing loopback DNS queries.

Packet-level reproduction
  1. Start a DNS packet capture in WSL2, for example:
sudo tcpdump -ni any -tttt -vv 'port 53'
  1. Run:
codex login --device-auth
  1. Complete the device authorization in the browser.

  2. Observe during the polling phase that DNS requests for auth.openai.com are sent to the configured WSL resolver and receive normal responses.

  3. Immediately after successful browser approval, observe a fresh DNS lookup for auth.openai.com being sent to 127.0.0.1:53 instead of the configured resolver. In this environment nothing listens on loopback port 53, so the lookup receives no response and is retransmitted.

  4. The final /oauth/token exchange then fails with the transport error above.

Additional checks

The following were independently checked in the same environment:

  • auth.openai.com is reachable from the same WSL2 environment.
  • Fresh curl processes can resolve the hostname, establish TCP/TLS, and POST to the same /oauth/token endpoint successfully.
  • The configured WSL resolver answers promptly during the same Codex login run.
  • No DNS listener is present on 127.0.0.1:53.
  • Disabling IPv6 does not change the failure.
  • The behavior reproduces on both 0.152.1 and 0.153.0.
Relevant Codex source path

The final exchange uses a newly constructed auth client via create_raw_auth_client(...), which calls:

auth_route_config
    .http_client_factory()
    .build_client_without_request_logging(endpoint, ClientRouteClass::Auth)

This is consistent with the packet trace showing a fresh resolution attempt at the final exchange boundary.

I am not claiming the exact internal reason that this fresh client selects 127.0.0.1:53; that lower-level mechanism is still unresolved. The packet-level behavior itself is directly observed.

Expected behavior

The fresh auth-exchange client should use a valid resolver for the active runtime, consistent with the resolver used by the successful polling path.

Actual behavior

After browser approval, the fresh auth-exchange client sends DNS queries for auth.openai.com to 127.0.0.1:53, where no DNS server is running, and the final OAuth token exchange fails before TCP connection establishment.

Related issues

Similar top-level token-exchange symptoms have been reported in #40839 and #41434, but those reports describe different environments and do not identify this WSL2 packet-level resolver switch to loopback during the final exchange.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at create_raw_auth_client(...) and the auth_route_config().http_client_factory().build_client_without_request_logging(...) path, then compare it with the client used by the successful polling flow. Reproduce under WSL2 with the provided tcpdump command and verify which resolver each client uses. Done means the final token exchange resolves auth.openai.com through the active configured resolver instead of 127.0.0.1:53.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
authentication, networking
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.