Skip to content

fix(auth): keep Codex OAuth pool accounts distinct on add + re-auth (#39236) - #42316

Merged
teknium1 merged 2 commits into
mainfrom
hermes/hermes-dcb0a7cd
Jun 8, 2026
Merged

fix(auth): keep Codex OAuth pool accounts distinct on add + re-auth (#39236)#42316
teknium1 merged 2 commits into
mainfrom
hermes/hermes-dcb0a7cd

Conversation

@teknium1

@teknium1 teknium1 commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Summary

hermes auth add openai-codex now keeps multiple ChatGPT OAuth accounts distinct in the credential pool — both when adding them and when re-authenticating one. Previously a second account silently collapsed into the latest login, so rotation/failover always used one account.

Closes #39236 (and the duplicate add-path issue tracked by #32664).

Root cause — two paths, both collapsing accounts

  1. Add pathhermes auth add openai-codex routed through the singleton _save_codex_tokens save, which writes providers.openai-codex.tokens and mirrors it into one device_code pool entry. A second add overwrote that singleton mirror instead of creating an independent entry, so two labels shared one token pair.
  2. Re-auth path_sync_codex_pool_entries() (from the openai-codex OAuth reauthorization can leave stale credential; auth add workaround required #33538 fix) refreshed every manual:device_code entry on any re-auth, clobbering independent accounts with the newest tokens.

Changes

manual:device_code pool entries refresh from their own token pair (_sync_codex_entry_from_auth_store only adopts the singleton for source=="device_code"), so they need no providers.openai-codex shadow.

Validation

E2E (isolated HERMES_HOME, real auth_add_command / _save_codex_tokens):

Scenario Before After
Add acctA then acctB 1 entry, acctB token under acctA label 2 entries, distinct tokens
Re-auth acctA with acctB + legacy-alias + singleton present independent accounts clobbered singleton + legacy alias refreshed, independent accounts untouched

pytest tests/hermes_cli/test_auth_commands.py tests/hermes_cli/test_auth_codex_provider.py → 79 passed. tests/agent/test_credential_pool.py → 78 passed.

Credit

Infographic

Codex multi-account credential pool fix

temalo and others added 2 commits June 8, 2026 11:37
The #33538 fix refreshed every credential_pool entry with source
"manual:device_code" on every Codex OAuth re-auth, on the assumption that
such entries were always legacy aliases of the singleton from the #33000
workaround era. That assumption is no longer true: `hermes auth add
openai-codex` also produces "manual:device_code" entries for independent
ChatGPT accounts, and the broad sync silently clobbered them with the
latest-authenticated token pair (labels preserved, token material
overwritten, status / quota readings then lie).

Narrow the sync: refresh a "manual:device_code" entry only when its
existing access_token matches the previous singleton access_token (true
legacy alias). Entries with distinct token material represent independent
accounts and are now left alone. Error markers are cleared only on
entries actually rewritten, so an independent account's own 429 / 401
state survives a re-auth that targeted a different account.

Tests:
* New: independent acctB/acctC are not overwritten when acctA re-auths.
* New: legacy singleton-alias still refreshed (preserves #33538).
* New: missing previous singleton state handled (no crash, no false
  alias match).
* New: access_token-only alias match (legacy schema without
  refresh_token still recognized).
* New: error markers cleared only on entries actually refreshed.
* Updated: existing manual-device-code sync test now covers both the
  legacy-alias path AND the independent-account path in one fixture.

Behaviour change is zero for users with a single Codex account and zero
for users whose only "manual:device_code" entry is the legacy alias of
the singleton. Users with multiple independent Codex accounts added via
`hermes auth add` now keep their distinct token material across
re-auths.

Local: 29 passed in tests/hermes_cli/test_auth_codex_provider.py, no
new failures in tests/hermes_cli/ vs upstream/main baseline.

Fixes #39236.
hermes auth add openai-codex now creates an independent
manual:device_code pool entry per account instead of routing through
the singleton _save_codex_tokens save path, which collapsed every
added account into the latest login (the second add overwrote the
first account's singleton-mirrored device_code entry). This is the
add-path half of #39236; PR #39243 (already on this branch) fixes the
re-auth half.

manual:device_code entries refresh from their own token pair
(_sync_codex_entry_from_auth_store only adopts the singleton for
source=="device_code"), so they need no providers.openai-codex
shadow. Adding the first credential marks openai-codex active (the
singleton path did this implicitly) so the setup wizard's
get_active_provider() check still passes; subsequent adds leave the
active provider untouched.

Adds SOURCE_MANUAL_DEVICE_CODE constant and a regression test that two
distinct accounts keep distinct token pairs. Updates two existing add
tests to the pool-only behavior.

Co-authored-by: glesperance <info@glesperance.com>
@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

🔎 Lint report: hermes/hermes-dcb0a7cd vs origin/main

ruff

Total: 0 on HEAD, 0 on base (➖ 0)

🆕 New issues: none

✅ Fixed issues: none

Unchanged: 0 pre-existing issues carried over.

ty (type checker)

Total: 10506 on HEAD, 10507 on base (✅ -1)

🆕 New issues: none

✅ Fixed issues (1):

Rule Count
invalid-argument-type 1
First entries
hermes_cli/auth_commands.py:317: [invalid-argument-type] invalid-argument-type: Argument to function `_save_codex_tokens` is incorrect: Expected `str`, found `Any | None`

Unchanged: 5518 pre-existing issues carried over.

Diagnostics are surfaced as warnings — this check never fails the build.

@alt-glitch alt-glitch added type/bug Something isn't working P3 Low — cosmetic, nice to have area/auth Authentication, OAuth, credential pools provider/openai OpenAI / Codex Responses API codex labels Jun 8, 2026
@teknium1
teknium1 merged commit c78b3e1 into main Jun 8, 2026
23 checks passed
@teknium1
teknium1 deleted the hermes/hermes-dcb0a7cd branch June 8, 2026 18:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/auth Authentication, OAuth, credential pools codex P3 Low — cosmetic, nice to have provider/openai OpenAI / Codex Responses API type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: openai-codex OAuth add/reauth overwrites existing credential-pool entries while preserving stale labels

3 participants