Skip to content

fix(auth): clear active_provider when removing the active OAuth provider - #37648

Open
AhmetArif0 wants to merge 1 commit into
NousResearch:mainfrom
AhmetArif0:fix/auth-remove-clear-active-provider
Open

fix(auth): clear active_provider when removing the active OAuth provider#37648
AhmetArif0 wants to merge 1 commit into
NousResearch:mainfrom
AhmetArif0:fix/auth-remove-clear-active-provider

Conversation

@AhmetArif0

Copy link
Copy Markdown
Contributor

Problem

_clear_auth_store_provider() deletes providers[provider] from auth.json but does not
update active_provider. After removal, get_active_provider() still returns the stale
provider name. On the next launch is_provider_explicitly_configured() returns True for
it, credential-pool resolution finds an empty pool, and raises "No inference provider
configured"
— even when other providers are still available.

Affected providers

All providers whose removal dispatches through _clear_auth_store_provider:
nous, openai-codex, xai-oauth, minimax-oauth
(and any future provider that calls it).

Failure path

hermes auth add xai-oauth      # active_provider = "xai-oauth"
hermes auth remove xai-oauth   # providers["xai-oauth"] deleted
                                # active_provider = "xai-oauth"  ← stale
hermes                         # get_active_provider() → "xai-oauth"
                                # load_pool("xai-oauth") → empty
                                # → "No inference provider configured"

Fix

clear_provider_auth() (used by hermes logout) already nulls active_provider when it
matches the removed provider (auth.py:1412-1413). Apply the same guard inside _clear_auth_store_provider():

del providers_dict[provider]
if auth_store.get("active_provider") == provider:
    auth_store["active_provider"] = None
_save_auth_store(auth_store)

Both changes happen inside the same _auth_store_lock() context, so the write is atomic.

Test plan

  • test_clear_auth_store_provider_clears_active_provider — removes the active provider, verifies active_provider is None
  • test_clear_auth_store_provider_preserves_active_provider_for_other — removes a non-active provider, verifies active_provider is unchanged
  • All existing credential_sources tests pass

_clear_auth_store_provider() deleted providers[provider] from auth.json
but left active_provider pointing to the removed provider. On the next
launch get_active_provider() returned the stale name, credential-pool
resolution found an empty pool, and raised "No inference provider
configured" even when other providers were available.

clear_provider_auth() (used by hermes logout) already clears
active_provider at line 1412-1413. Apply the same guard in
_clear_auth_store_provider() so every auth-remove path stays in sync.
@alt-glitch alt-glitch added type/bug Something isn't working P3 Low — cosmetic, nice to have comp/cli CLI entry point, hermes_cli/, setup wizard area/auth Authentication, OAuth, credential pools labels Jun 2, 2026

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for identifying the stale active_provider state. Current main still has the singleton-backed bug at agent/credential_sources.py:233-236, but the proposed condition needs one adjustment before it covers all active OAuth removals.

Problems

  • The new guard remains inside the singleton-membership branch. Current Codex adds intentionally create pool-only manual:device_code entries (hermes_cli/auth_commands.py:316-324), while the removal registry routes that source to _remove_codex_device_code() (agent/credential_sources.py:415-417). With no providers.openai-codex entry, the proposed guard never runs and leaves the active provider stale.

Suggested changes

  • Clear and persist active_provider whenever it matches the requested provider, independently of whether a singleton was deleted; retain the helper's deletion-return semantics if needed for user-facing cleanup output.
  • Add an auth_remove_command() regression for an active, pool-only Codex manual:device_code entry and assert active_provider is cleared.

Automated hermes-sweeper review.

providers_dict = auth_store.get("providers")
if isinstance(providers_dict, dict) and provider in providers_dict:
del providers_dict[provider]
if auth_store.get("active_provider") == provider:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This guard only runs when providers[provider] still exists. Current hermes auth add openai-codex intentionally creates pool-only manual:device_code credentials (hermes_cli/auth_commands.py:316-324), and their removal is routed here via the Codex removal step. Clear and persist active_provider independently of singleton deletion so that active pool-only credentials do not leave stale provider state.

@teknium1 teknium1 added sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 13, 2026
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 comp/cli CLI entry point, hermes_cli/, setup wizard P3 Low — cosmetic, nice to have sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants