OpenAI Codex Multi OAuth
Support and debug more than one openai-codex OAuth login inside OpenClaw.
Start here
- Run
python3 scripts/summarize_codex_profiles.py. - Classify the bug before patching anything.
- Change the smallest wrong layer.
- Re-test after every change.
If the target setup includes a local helper command or router script, reproduce through that real entrypoint at least once. Synthetic env-injected tests can miss session-sync bugs.
Mental model
Treat these as separate layers:
- stored preference — any saved local pointer such as
codex_profile_id - auth order —
order.openai-codexin the auth store - session override —
authProfileOverridefor the current chat/session - effective runtime profile — the profile that actually handled the request after selection or failover
- usage source — the token/accountId used by usage-fetch logic
- display metadata — the label shown to the user, such as email/workspace
- optional external profile repo — a separate file or store that keeps multiple Codex OAuth identities while runtime uses one active slot
Do not assume these layers always match.
Common architectures
A. Native auth-store setup
OpenClaw stores multiple openai-codex:* profiles directly in auth-profiles.json, and runtime resolves selection from auth order plus session override.
B. External-router setup
A local repo of Codex OAuth identities exists outside normal runtime selection, and a helper/router copies one selected profile into an active slot such as openai-codex:default.
In that design, verify all of these separately:
- repo profile selected by the router
- active slot content after routing
- current session
authProfileOverride /statusoauth label/statususage source
Decision tree
1) The wrong account is selected
Check in this order:
- stored preference or helper-selected profile
order.openai-codex- session
authProfileOverride - effective runtime profile
- whether failover is expected or a bug
2) /codex_profile-style helper switches profile, but /status does not follow
Check:
- whether the helper changed only the active slot or also the current session override
- whether the current chat/session was correctly identified
- whether the environment that invokes the helper is missing chat/session metadata
- whether the platform keeps companion session entries that also need syncing
If the helper is real, re-test through the real command path, not only manual edits.
3) /status oauth changes, but usage does not
Check:
- current session
authProfileOverride - the effective runtime profile for the current chat
- whether the usage loader resolves auth from generic provider order instead of the current session profile
- whether the UI is mixing preferred-profile and effective-profile semantics
4) A profile works sometimes but not always
Check:
- cooldown / last-good logic
- token expiry
- soft-pin vs hard-pin semantics
- whether failover is expected behavior or a bug
5) A token or profile entry is broken
Check:
- whether the same
accountIdexists in another store or backup - whether only one profile entry can be restored surgically
- whether local token parsing fails before request dispatch
6) /status, display labels, and runtime truth disagree
Decide which semantic each surface should represent:
- preferred profile
- effective runtime profile
- usage source profile
- display metadata label
Then verify every layer against that semantic before patching.
Stable design rules
- Prefer profile identity by
accountIdbefore email when possible. - Preserve different workspaces/accounts as separate profiles even when email matches.
- Keep profile ids stable, for example:
openai-codex:defaultopenai-codex:secondaryopenai-codex:tertiaryopenai-codex:account-N
- Do not blur preferred profile, effective runtime profile, and usage source profile.
- If an external repo exists, treat it as a separate layer instead of silently merging it into runtime state.
Validation checklist
After each change, verify all of these:
- stored preference or helper-selected profile is what you expect
- auth order is what you expect
- current session
authProfileOverrideis what you expect - runtime actually uses the intended profile
/statusshows the intended semantic- usage matches the intended semantic, or the difference is explicitly understood
- any helper command resolves the same profile id the runtime is using
Bundled resources
- Read
references/runtime-files.mdfor the file families that usually matter. - Read
references/workflows.mdfor concrete repair workflows and rollback points. - Run
scripts/summarize_codex_profiles.pybefore and after changes.
Guardrails
- Back up auth files or runtime bundles before editing them.
- Prefer surgical patches over broad rewrites.
- Keep version-specific assumptions explicit.
- Do not restart the gateway unless the user asked.
- Commit workspace skill changes after edits.