Skip to content

fix(acp): require tokens key before selecting chatgpt auth method#3628

Draft
simonrosenberg wants to merge 1 commit into
mainfrom
openhands/fix-acp-auth-format-check-3627
Draft

fix(acp): require tokens key before selecting chatgpt auth method#3628
simonrosenberg wants to merge 1 commit into
mainfrom
openhands/fix-acp-auth-format-check-3627

Conversation

@simonrosenberg

@simonrosenberg simonrosenberg commented Jun 10, 2026

Copy link
Copy Markdown
Member

H:

  • A human has tested these changes.

AGENT:


Why

When acp_isolate_data_dir=True and codex-acp is driven with API-key auth
(OPENAI_API_KEY only, no CODEX_AUTH_JSON), the first session/new
succeeds, and during that session codex rewrites $CODEX_HOME/auth.json
with {"auth_mode": "apikey", "OPENAI_API_KEY": "..."}.

On the next launch (pod recycle / agent-server restart) _select_auth_method
in acp_agent.py saw the file at _codex_auth_file(env) and returned
"chatgpt", because the check only verified file presence:

if "chatgpt" in method_ids and _codex_auth_file(env).is_file():
    return "chatgpt"

codex-acp then read the apikey-format file as if it were a ChatGPT token
blob and hung indefinitely waiting for browser-based OAuth.

The production cloud path is unaffected — canvas always sends
CODEX_AUTH_JSON so the SDK materialises a proper chatgpt-format
auth.json before codex starts and codex never overwrites it. The bug
only manifested in test harnesses / non-standard deployments running with
API-key auth and acp_isolate_data_dir=True (discovered during the ACP
cloud pivot local validation, canvas#1290).

Summary

  • Add _codex_auth_file_is_chatgpt(env) which parses auth.json and
    requires a top-level "tokens" key — the marker that distinguishes
    the ChatGPT subscription token blob from the apikey-mode file codex
    writes for itself.
  • Gate the chatgpt branch in _select_auth_method on this stricter
    check so an apikey-format file falls through to the
    openai-api-key / codex-api-key fallback instead of triggering
    the OAuth hang.
  • Update existing fixtures that wrote {} as auth.json to use the
    real chatgpt-format payload, and add two new tests:
    test_apikey_format_auth_file_falls_back_to_api_key (reproduces the
    bug from fix(acp): _select_auth_method picks chatgpt when $CODEX_HOME/auth.json is in apikey format, causing auth hang on resume #3627) and test_malformed_auth_file_falls_back_to_api_key
    (defensive coverage for unreadable / non-JSON files).

Issue Number

Fixes #3627

How to Test

uv run pytest tests/sdk/agent/test_acp_agent.py::TestSelectAuthMethod -x -q

Result: 20 passed, including the two new tests
(test_apikey_format_auth_file_falls_back_to_api_key,
test_malformed_auth_file_falls_back_to_api_key) that fail on main
and pass with this change.

End-to-end repro (matches the issue's reproduction sequence):

  1. Create an ACPAgent conversation with acp_isolate_data_dir=True,
    OPENAI_API_KEY in secrets (no CODEX_AUTH_JSON).
  2. First turn completes via openai-api-key. codex-acp writes
    $CODEX_HOME/auth.json with {"auth_mode": "apikey", ...}.
  3. Restart the agent-server.
  4. Send a follow-up message. With this fix, _select_auth_method
    returns "openai-api-key" (file does not contain "tokens")
    instead of "chatgpt", and the conversation proceeds without
    hanging on browser-based OAuth.

Video/Screenshots

N/A — auth-path selection change, exercised through the new unit tests.

Type

  • Bug fix
  • Feature
  • Refactor
  • Breaking change
  • Docs / chore

Notes

  • Behavior is unchanged on the production cloud path (CODEX_AUTH_JSON
    materialises a proper chatgpt-format file with "tokens").
  • The helper accepts only dicts containing "tokens"; malformed or
    non-dict JSON also falls back to the API-key path, which is the safe
    default.

This PR was created by an AI agent (OpenHands) on behalf of the user.

@simonrosenberg can click here to continue refining the PR


Agent Server images for this PR

GHCR package: https://github.com/OpenHands/agent-sdk/pkgs/container/agent-server

Variants & Base Images

Variant Architectures Base Image Docs / Tags
java amd64, arm64 eclipse-temurin:17-jdk Link
python amd64, arm64 nikolaik/python-nodejs:python3.13-nodejs22-slim Link
golang amd64, arm64 golang:1.21-bookworm Link

Pull (multi-arch manifest)

# Each variant is a multi-arch manifest supporting both amd64 and arm64
docker pull ghcr.io/openhands/agent-server:42e8d04-python

Run

docker run -it --rm \
  -p 8000:8000 \
  --name agent-server-42e8d04-python \
  ghcr.io/openhands/agent-server:42e8d04-python

All tags pushed for this build

ghcr.io/openhands/agent-server:42e8d04-golang-amd64
ghcr.io/openhands/agent-server:42e8d043fb0631e647cb41617ea597890f9c1d85-golang-amd64
ghcr.io/openhands/agent-server:openhands-fix-acp-auth-format-check-3627-golang-amd64
ghcr.io/openhands/agent-server:42e8d04-golang_tag_1.21-bookworm-amd64
ghcr.io/openhands/agent-server:42e8d04-golang-arm64
ghcr.io/openhands/agent-server:42e8d043fb0631e647cb41617ea597890f9c1d85-golang-arm64
ghcr.io/openhands/agent-server:openhands-fix-acp-auth-format-check-3627-golang-arm64
ghcr.io/openhands/agent-server:42e8d04-golang_tag_1.21-bookworm-arm64
ghcr.io/openhands/agent-server:42e8d04-java-amd64
ghcr.io/openhands/agent-server:42e8d043fb0631e647cb41617ea597890f9c1d85-java-amd64
ghcr.io/openhands/agent-server:openhands-fix-acp-auth-format-check-3627-java-amd64
ghcr.io/openhands/agent-server:42e8d04-eclipse-temurin_tag_17-jdk-amd64
ghcr.io/openhands/agent-server:42e8d04-java-arm64
ghcr.io/openhands/agent-server:42e8d043fb0631e647cb41617ea597890f9c1d85-java-arm64
ghcr.io/openhands/agent-server:openhands-fix-acp-auth-format-check-3627-java-arm64
ghcr.io/openhands/agent-server:42e8d04-eclipse-temurin_tag_17-jdk-arm64
ghcr.io/openhands/agent-server:42e8d04-python-amd64
ghcr.io/openhands/agent-server:42e8d043fb0631e647cb41617ea597890f9c1d85-python-amd64
ghcr.io/openhands/agent-server:openhands-fix-acp-auth-format-check-3627-python-amd64
ghcr.io/openhands/agent-server:42e8d04-nikolaik_s_python-nodejs_tag_python3.13-nodejs22-slim-amd64
ghcr.io/openhands/agent-server:42e8d04-python-arm64
ghcr.io/openhands/agent-server:42e8d043fb0631e647cb41617ea597890f9c1d85-python-arm64
ghcr.io/openhands/agent-server:openhands-fix-acp-auth-format-check-3627-python-arm64
ghcr.io/openhands/agent-server:42e8d04-nikolaik_s_python-nodejs_tag_python3.13-nodejs22-slim-arm64
ghcr.io/openhands/agent-server:42e8d04-golang
ghcr.io/openhands/agent-server:42e8d043fb0631e647cb41617ea597890f9c1d85-golang
ghcr.io/openhands/agent-server:openhands-fix-acp-auth-format-check-3627-golang
ghcr.io/openhands/agent-server:42e8d04-golang_tag_1.21-bookworm
ghcr.io/openhands/agent-server:42e8d04-java
ghcr.io/openhands/agent-server:42e8d043fb0631e647cb41617ea597890f9c1d85-java
ghcr.io/openhands/agent-server:openhands-fix-acp-auth-format-check-3627-java
ghcr.io/openhands/agent-server:42e8d04-eclipse-temurin_tag_17-jdk
ghcr.io/openhands/agent-server:42e8d04-python
ghcr.io/openhands/agent-server:42e8d043fb0631e647cb41617ea597890f9c1d85-python
ghcr.io/openhands/agent-server:openhands-fix-acp-auth-format-check-3627-python
ghcr.io/openhands/agent-server:42e8d04-nikolaik_s_python-nodejs_tag_python3.13-nodejs22-slim

About Multi-Architecture Support

  • Each variant tag (e.g., 42e8d04-python) is a multi-arch manifest supporting both amd64 and arm64
  • Docker automatically pulls the correct architecture for your platform
  • Individual architecture tags (e.g., 42e8d04-python-amd64) are also available if needed

When codex-acp runs in apikey mode it rewrites $CODEX_HOME/auth.json with
{"auth_mode": "apikey", "OPENAI_API_KEY": "..."}. On the next launch
_select_auth_method saw the file and returned 'chatgpt' — but the payload
is in apikey format, so codex hung forever waiting for browser-based OAuth.

Gate chatgpt selection on the presence of the 'tokens' key (the ChatGPT
subscription token blob) rather than mere file existence.

Co-authored-by: openhands <openhands@all-hands.dev>
@github-actions

Copy link
Copy Markdown
Contributor

Python API breakage checks — ✅ PASSED

Result:PASSED

Action log

@github-actions

Copy link
Copy Markdown
Contributor

REST API breakage checks (OpenAPI) — ✅ PASSED

Result:PASSED

Action log

@github-actions

Copy link
Copy Markdown
Contributor

Coverage

Coverage Report •
FileStmtsMissCoverMissing
openhands-sdk/openhands/sdk/agent
   acp_agent.py114510191%735–737, 974–975, 1018, 1020, 1024, 1028, 1054, 1117–1118, 1123, 1190, 1504, 1507–1508, 1525–1526, 1562, 1567, 1645, 1650, 1984–1985, 2269–2272, 2276–2278, 2281–2285, 2287, 2505, 2519–2520, 2523–2525, 2533, 2537, 2541–2542, 2548–2549, 2561–2562, 2565, 2599, 2603–2605, 2609–2610, 2642, 2726, 2913–2915, 2918–2919, 2959, 3101, 3105, 3113–3115, 3153–3154, 3157, 3165–3167, 3169, 3171, 3175, 3178, 3187–3189, 3191, 3227–3228, 3246–3249, 3252, 3256–3258, 3260, 3264–3265, 3473–3474
TOTAL29933840771% 

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(acp): _select_auth_method picks chatgpt when $CODEX_HOME/auth.json is in apikey format, causing auth hang on resume

2 participants