Skip to content

auth: Codex OAuth cancel doesn't stop device-code worker; can still write token to wrong profile #74308

Description

@JoaoMarcos44

Summary

Cancelling an OpenAI Codex device-code OAuth flow does not stop the background polling worker, and if the user authorizes anyway after cancelling, credentials are still written — potentially to the wrong profile.

Root cause

  • The poll loop (hermes_cli/web_server.py, around the while time.monotonic() < deadline: ... block near line 11296) never re-checks whether the session was cancelled.
  • The target profile is resolved lazily via _oauth_session_profile(session_id) only at write time (~line 11347), not captured up front.
  • DELETE /api/providers/oauth/sessions/{session_id} (~line 11444) only does _oauth_sessions.pop(session_id, None) — no cancellation token/event, and it does not signal the worker thread.
  • After the pop, _oauth_session_profile(session_id) returns None (session no longer in the dict), which falls through to whatever profile is "current" at completion time, not the profile that was originally selected when the flow started.

Impact

  • User believes the auth flow was aborted, but credentials may still be written later.
  • Credentials can land in the wrong (current/default) profile instead of the originally targeted one, breaking profile isolation.
  • The worker keeps consuming a thread/polling the provider until session expiry even after cancel.

Suggested fix (root cause)

  • Track cancellation via a per-session event/flag, checked before every poll iteration, before the code exchange, and before the token write.
  • Capture the validated target profile once at session start (immutable for the life of the worker) instead of re-resolving it at write time.
  • Require the session to still exist, be uncancelled, and match the same provider/profile before persisting tokens.

Reproduction

Local deterministic repro built with TestClient, fake HTTP responses, and sentinel tokens: worker paused right after publishing the device code, DELETE called, poll then approved. Result: cancel endpoint returns 200, session removed, but the worker still finishes and calls the token-save path once, with the profile scope resolved to None instead of the original profile.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Medium — degraded but workaround existsarea/authAuthentication, OAuth, credential poolsarea/profilesMulti-profile isolation, HERMES_HOME scopingcomp/cliCLI entry point, hermes_cli/, setup wizardduplicateThis issue or pull request already existsprovider/openaiOpenAI / Codex Responses APIsweeper:risk-compatibilitySweeper risk: may break existing users, config, migrations, defaults, or upgradessweeper:risk-security-boundarySweeper risk: may affect sandboxing, auth, credentials, or sensitive datatype/securitySecurity vulnerability or hardening

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions