Skip to content

fix(xai-oauth): surface tier-gated 403 with API-key fallback (closes #26847) - #28351

Merged
teknium1 merged 3 commits into
mainfrom
hermes/hermes-6063e704
May 19, 2026
Merged

fix(xai-oauth): surface tier-gated 403 with API-key fallback (closes #26847)#28351
teknium1 merged 3 commits into
mainfrom
hermes/hermes-6063e704

Conversation

@teknium1

Copy link
Copy Markdown
Contributor

Salvage of #26855 (@xxxigm).

Summary

Makes the xai-oauth provider fail gracefully when xAI's backend returns HTTP 403 to a standard SuperGrok subscriber (subscription is active but the account is not on xAI's API-access allowlist). Stops the credential-pool refresh-loop and surfaces a useful error pointing at the XAI_API_KEY fallback.

Changes

  • hermes_cli/auth.py: split 403 off from 400/401 in refresh_xai_oauth_pure and _xai_oauth_exchange_code_for_tokens — new xai_oauth_tier_denied error code with relogin_required=False. Loopback-exchange port was adapted to the current _xai_oauth_exchange_code_for_tokens helper shape (the PR's pre-refactor inline httpx.post block was already replaced by this helper on main).
  • agent/agent_runtime_helpers.py (was run_agent.py in the original PR — relocated to the refactored recover_with_credential_pool forwarder target): defense-in-depth — any 403 on xai-oauth is treated as entitlement to stop the refresh loop even when the body fails the existing _is_entitlement_failure keyword set.
  • website/docs/guides/xai-grok-oauth.md: drops the inaccurate "(any active tier)" claim, adds a Troubleshooting section for the HTTP 403 path with the XAI_API_KEY fallback recipe.

Validation

  • scripts/run_tests.sh tests/hermes_cli/test_auth_xai_oauth_provider.py tests/run_agent/test_codex_xai_oauth_recovery.py -q → 98/98 passing.
  • scripts/run_tests.sh tests/agent/test_credential_pool.py -q → 52/52 passing (no regression in the related auth/pool tests).

Authorship preserved across 3 commits (cherry-pick + conflict resolution against current main).

xxxigm added 3 commits May 18, 2026 20:05
…dpoint

xAI's token endpoint returns HTTP 403 to the OAuth grant when the
account isn't on the allowlist for API access (e.g. standard
SuperGrok subscribers — see #26847). Treating it like a stale-token
400/401 made ``format_auth_error`` append "Run ``hermes model`` to
re-authenticate", which is misleading because re-login can't change
xAI's tier decision.

Split 403 off in both ``refresh_xai_oauth_pure`` and the loopback
login token exchange:

* New error code ``xai_oauth_tier_denied`` with ``relogin_required=False``
* Message explains the entitlement gate and points at the
  ``XAI_API_KEY`` + ``provider: xai`` fallback
* 400/401 still set ``relogin_required=True`` as before
* 5xx still set ``relogin_required=False`` as before
…resh-loop

The existing ``_is_entitlement_failure`` heuristic only fires when
the response body contains specific substrings ("do not have an
active Grok subscription", etc.). xAI has been seen to 403 standard
SuperGrok subscribers with a terser body that doesn't match those
keywords (#26847), and the recovery path would then mint a fresh
token, get a fresh 403, and loop until Ctrl+C.

Add a defense-in-depth check at the recovery call site: any 403 on
``provider == "xai-oauth"`` short-circuits ``try_refresh_current``
so the error surfaces immediately with the friendly hint from
``_summarize_api_error``. Keeps the existing keyword path for all
other providers untouched.
Tests:

* ``test_refresh_xai_oauth_pure_403_marked_tier_denied_not_relogin`` —
  refresh-403 raises ``xai_oauth_tier_denied`` with
  ``relogin_required=False`` and the API-key fallback hint in body.
* ``test_format_auth_error_tier_denied_does_not_suggest_relogin`` —
  the renderer does not append "Run ``hermes model``" for the new
  code.
* ``test_recover_with_credential_pool_skips_refresh_on_bare_403_for_xai_oauth`` —
  bare ``{"reason":"forbidden","message":"Forbidden"}`` body (which
  does not match the existing keyword heuristic) still short-circuits
  ``try_refresh_current`` on xai-oauth.

Docs:

* Drop the "(any active tier)" claim from the xai-grok-oauth guide,
  add a top-of-page warning callout, and a Troubleshooting section
  for the 403-after-login case pointing at ``XAI_API_KEY`` +
  ``provider: xai`` as the documented fallback.
@teknium1
teknium1 merged commit 34f34ba into main May 19, 2026
17 of 18 checks passed
@teknium1
teknium1 deleted the hermes/hermes-6063e704 branch May 19, 2026 03:08
@github-actions

Copy link
Copy Markdown
Contributor

🔎 Lint report: hermes/hermes-6063e704 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: 8791 on HEAD, 8791 on base (➖ 0)

🆕 New issues: none

✅ Fixed issues: none

Unchanged: 4626 pre-existing issues carried over.

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

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.

2 participants