mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-23 05:31:23 +00:00
feat(xai-oauth): add xAI Grok OAuth (SuperGrok Subscription) provider
Adds a new authentication provider that lets SuperGrok subscribers sign in to Hermes with their xAI account via the standard OAuth 2.0 PKCE loopback flow, instead of pasting a raw API key from console.x.ai. Highlights ---------- * OAuth 2.0 PKCE loopback login against accounts.x.ai with discovery, state/nonce, and a strict CORS-origin allowlist on the callback. * Authorize URL carries `plan=generic` (required for non-allowlisted loopback clients) and `referrer=hermes-agent` for best-effort attribution in xAI's OAuth server logs. * Token storage in `auth.json` with file-locked atomic writes; JWT `exp`-based expiry detection with skew; refresh-token rotation synced both ways between the singleton store and the credential pool so multi-process / multi-profile setups don't tear each other's refresh tokens. * Reactive 401 retry: on a 401 from the xAI Responses API, the agent refreshes the token, swaps it back into `self.api_key`, and retries the call once. Guarded against silent account swaps when the active key was sourced from a different (manual) pool entry. * Auxiliary tasks (curator, vision, embeddings, etc.) route through a dedicated xAI Responses-mode auxiliary client instead of falling back to OpenRouter billing. * Direct HTTP tools (`tools/xai_http.py`, transcription, TTS, image-gen plugin) resolve credentials through a unified runtime → singleton → env-var fallback chain so xai-oauth users get them for free. * `hermes auth add xai-oauth` and `hermes auth remove xai-oauth N` are wired through the standard auth-commands surface; remove cleans up the singleton loopback_pkce entry so it doesn't silently reinstate. * `hermes model` provider picker shows "xAI Grok OAuth (SuperGrok Subscription)" and the model-flow falls back to pool credentials when the singleton is missing. Hardening --------- * Discovery and refresh responses validate the returned `token_endpoint` host against the same `*.x.ai` allowlist as the authorization endpoint, blocking MITM persistence of a hostile endpoint. * Discovery / refresh / token-exchange `response.json()` calls are wrapped to raise typed `AuthError` on malformed bodies (captive portals, proxy error pages) instead of leaking JSONDecodeError tracebacks. * `prompt_cache_key` is routed through `extra_body` on the codex transport (sending it as a top-level kwarg trips xAI's SDK with a TypeError). * Credential-pool sync-back preserves `active_provider` so refreshing an OAuth entry doesn't silently flip the active provider out from under the running agent. Testing ------- * New `tests/hermes_cli/test_auth_xai_oauth_provider.py` (~63 tests) covers JWT expiry, OAuth URL params (plan + referrer), CORS origins, redirect URI validation, singleton↔pool sync, concurrency races, refresh error paths, runtime resolution, and malformed-JSON guards. * Extended `test_credential_pool.py`, `test_codex_transport.py`, and `test_run_agent_codex_responses.py` cover the pool sync-back, `extra_body` routing, and 401 reactive refresh paths. * 165 tests passing on this branch via `scripts/run_tests.sh`.
This commit is contained in:
parent
9fb40e6a3d
commit
b62c997973
27 changed files with 3843 additions and 131 deletions
214
website/docs/guides/xai-grok-oauth.md
Normal file
214
website/docs/guides/xai-grok-oauth.md
Normal file
|
|
@ -0,0 +1,214 @@
|
|||
---
|
||||
sidebar_position: 16
|
||||
title: "xAI Grok OAuth (SuperGrok Subscription)"
|
||||
description: "Sign in with your SuperGrok subscription to use Grok models in Hermes Agent — no API key required"
|
||||
---
|
||||
|
||||
# xAI Grok OAuth (SuperGrok Subscription)
|
||||
|
||||
Hermes Agent supports xAI Grok through a browser-based OAuth login flow against [accounts.x.ai](https://accounts.x.ai), using your existing **SuperGrok subscription**. No `XAI_API_KEY` is required — log in once and Hermes automatically refreshes your session in the background.
|
||||
|
||||
The transport reuses the `codex_responses` adapter (xAI exposes a Responses-style endpoint), so reasoning, tool-calling, streaming, and prompt caching work without any adapter changes.
|
||||
|
||||
The same OAuth bearer token is also reused by every direct-to-xAI surface in Hermes — TTS, image generation, video generation, and transcription — so a single login covers all four.
|
||||
|
||||
## Overview
|
||||
|
||||
| Item | Value |
|
||||
|------|-------|
|
||||
| Provider ID | `xai-oauth` |
|
||||
| Display name | xAI Grok OAuth (SuperGrok Subscription) |
|
||||
| Auth type | Browser OAuth 2.0 PKCE (loopback callback) |
|
||||
| Transport | xAI Responses API (`codex_responses`) |
|
||||
| Default model | `grok-4.3` |
|
||||
| Endpoint | `https://api.x.ai/v1` |
|
||||
| Auth server | `https://accounts.x.ai` |
|
||||
| Requires env var | No (`XAI_API_KEY` is **not** used for this provider) |
|
||||
| Subscription | [SuperGrok](https://x.ai/grok) (any active tier) |
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Python 3.9+
|
||||
- Hermes Agent installed
|
||||
- An active SuperGrok subscription on your xAI account
|
||||
- A browser available on the local machine (or use `--no-browser` for remote sessions)
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
# Launch the provider and model picker
|
||||
hermes model
|
||||
# → Select "xAI Grok OAuth (SuperGrok Subscription)" from the provider list
|
||||
# → Hermes opens your browser to accounts.x.ai
|
||||
# → Approve access in the browser
|
||||
# → Pick a model (grok-4.3 is at the top)
|
||||
# → Start chatting
|
||||
|
||||
hermes
|
||||
```
|
||||
|
||||
After the first login, credentials are stored under `~/.hermes/auth.json` and refreshed automatically before they expire.
|
||||
|
||||
## Logging In Manually
|
||||
|
||||
You can trigger a login without going through the model picker:
|
||||
|
||||
```bash
|
||||
hermes auth add xai-oauth
|
||||
```
|
||||
|
||||
### Remote / headless sessions
|
||||
|
||||
On servers, containers, or SSH sessions where no browser is available, Hermes detects the remote environment and prints the authorization URL instead of opening a browser. Open the URL on any device with a browser, complete the consent flow, and Hermes finishes the loopback exchange when the redirect comes back.
|
||||
|
||||
If you need to force this behaviour explicitly:
|
||||
|
||||
```bash
|
||||
hermes auth add xai-oauth --no-browser
|
||||
```
|
||||
|
||||
## How the Login Works
|
||||
|
||||
1. Hermes opens your browser to `accounts.x.ai`.
|
||||
2. You sign in (or confirm your existing session) and approve access.
|
||||
3. xAI redirects back to Hermes and the tokens are saved to `~/.hermes/auth.json`.
|
||||
4. From then on, Hermes refreshes the access token in the background — you stay signed in until you `hermes auth remove xai-oauth` or revoke access from your xAI account settings.
|
||||
|
||||
## Checking Login Status
|
||||
|
||||
```bash
|
||||
hermes doctor
|
||||
```
|
||||
|
||||
The `◆ Auth Providers` section will show the current state of every provider, including `xai-oauth`.
|
||||
|
||||
## Switching Models
|
||||
|
||||
```bash
|
||||
hermes model
|
||||
# → Select "xAI Grok OAuth (SuperGrok Subscription)"
|
||||
# → Pick from the model list (grok-4.3 is pinned to the top)
|
||||
```
|
||||
|
||||
Or set the model directly:
|
||||
|
||||
```bash
|
||||
hermes config set model.default grok-4.3
|
||||
hermes config set model.provider xai-oauth
|
||||
```
|
||||
|
||||
## Configuration Reference
|
||||
|
||||
After login, `~/.hermes/config.yaml` will contain:
|
||||
|
||||
```yaml
|
||||
model:
|
||||
default: grok-4.3
|
||||
provider: xai-oauth
|
||||
base_url: https://api.x.ai/v1
|
||||
```
|
||||
|
||||
### Provider aliases
|
||||
|
||||
All of the following resolve to `xai-oauth`:
|
||||
|
||||
```bash
|
||||
hermes --provider xai-oauth # canonical
|
||||
hermes --provider grok-oauth # alias
|
||||
hermes --provider x-ai-oauth # alias
|
||||
hermes --provider xai-grok-oauth # alias
|
||||
```
|
||||
|
||||
## Direct-to-xAI Tools (TTS / Image / Video / Transcription)
|
||||
|
||||
Once you're logged in via OAuth, every direct-to-xAI tool reuses the same bearer token automatically — there is **no separate setup** unless you'd rather use an API key.
|
||||
|
||||
To pick a backend for each tool:
|
||||
|
||||
```bash
|
||||
hermes tools
|
||||
# → Text-to-Speech → "xAI TTS"
|
||||
# → Image Generation → "xAI Grok Imagine (image)"
|
||||
# → Video Generation → "xAI Grok Imagine"
|
||||
```
|
||||
|
||||
If OAuth tokens are already stored, the picker confirms it and skips the credential prompt. If neither OAuth nor `XAI_API_KEY` is set, the picker offers a 3-choice menu: OAuth login, paste API key, or skip.
|
||||
|
||||
:::note Video generation is off by default
|
||||
The `video_gen` toolset is disabled by default. Enable it in `hermes tools` → `🎬 Video Generation` (press space) before the agent can call `video_generate`. Otherwise the agent may fall back to the bundled ComfyUI skill, which is also tagged for video generation.
|
||||
:::
|
||||
|
||||
### Models
|
||||
|
||||
| Tool | Model | Notes |
|
||||
|------|-------|-------|
|
||||
| Chat | `grok-4.3` | Default; auto-selected when you log in via OAuth |
|
||||
| Chat | `grok-4.20-0309-reasoning` | Reasoning variant |
|
||||
| Chat | `grok-4.20-0309-non-reasoning` | Non-reasoning variant |
|
||||
| Chat | `grok-4.20-multi-agent-0309` | Multi-agent variant |
|
||||
| Image | `grok-imagine-image` | Default; ~5–10 s |
|
||||
| Image | `grok-imagine-image-quality` | Higher fidelity; ~10–20 s |
|
||||
| Video | `grok-imagine-video` | Text-to-video and image-to-video; up to 7 reference images |
|
||||
| TTS | (default voice) | xAI `/v1/tts` endpoint |
|
||||
|
||||
The chat catalog is derived live from the on-disk `models.dev` cache; new xAI releases appear automatically once that cache refreshes. `grok-4.3` is always pinned to the top of the list.
|
||||
|
||||
## Environment Variables
|
||||
|
||||
| Variable | Effect |
|
||||
|----------|--------|
|
||||
| `XAI_BASE_URL` | Override the default `https://api.x.ai/v1` endpoint (rarely needed). |
|
||||
| `HERMES_INFERENCE_PROVIDER` | Force the active provider at runtime, e.g. `HERMES_INFERENCE_PROVIDER=xai-oauth hermes`. |
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Token expired — not re-logging in automatically
|
||||
|
||||
Hermes refreshes the token before each session and again reactively on a 401. If refresh fails with `invalid_grant` (the refresh token was revoked, or the account was rotated), Hermes surfaces a typed re-auth message instead of crashing.
|
||||
|
||||
**Fix:** run `hermes auth add xai-oauth` again to start a fresh login.
|
||||
|
||||
### Authorization timed out
|
||||
|
||||
The loopback listener has a finite expiry window (default 180 s). If you don't approve the login in time, Hermes raises a timeout error.
|
||||
|
||||
**Fix:** re-run `hermes auth add xai-oauth` (or `hermes model`). The flow starts fresh.
|
||||
|
||||
### State mismatch (possible CSRF)
|
||||
|
||||
Hermes detected that the `state` value returned by the authorization server doesn't match what it sent.
|
||||
|
||||
**Fix:** re-run the login. If it persists, check for a proxy or redirect that is modifying the OAuth response.
|
||||
|
||||
### Logging in from a remote server
|
||||
|
||||
On SSH or container sessions Hermes prints the authorization URL instead of opening a browser. Open the URL on any device with a browser and complete the consent there — the loopback callback comes back to your remote host.
|
||||
|
||||
You can also force this behaviour:
|
||||
|
||||
```bash
|
||||
hermes auth add xai-oauth --no-browser
|
||||
```
|
||||
|
||||
### "No xAI credentials found" error at runtime
|
||||
|
||||
The auth store has no `xai-oauth` entry and no `XAI_API_KEY` is set. You haven't logged in yet, or the credential file was deleted.
|
||||
|
||||
**Fix:** run `hermes model` and pick the xAI Grok OAuth provider, or run `hermes auth add xai-oauth`.
|
||||
|
||||
## Logging Out
|
||||
|
||||
To remove stored xAI Grok OAuth credentials:
|
||||
|
||||
```bash
|
||||
hermes auth remove xai-oauth
|
||||
```
|
||||
|
||||
This clears both the singleton `loopback_pkce` entry in `auth.json` and any matching credential-pool rows.
|
||||
|
||||
## See Also
|
||||
|
||||
- [AI Providers reference](../integrations/providers.md)
|
||||
- [Environment Variables](../reference/environment-variables.md)
|
||||
- [Configuration](../user-guide/configuration.md)
|
||||
- [Voice & TTS](../user-guide/features/tts.md)
|
||||
|
|
@ -331,6 +331,8 @@ When using the Z.AI / GLM provider, Hermes automatically probes multiple endpoin
|
|||
|
||||
xAI is wired through the Responses API (`codex_responses` transport) for automatic reasoning support on Grok 4 models — no `reasoning_effort` parameter needed, the server reasons by default. Set `XAI_API_KEY` in `~/.hermes/.env` and pick xAI in `hermes model`, or drop `grok` as a shortcut into `/model grok-4-1-fast-reasoning`.
|
||||
|
||||
SuperGrok subscribers can sign in with browser OAuth instead of using an API key — pick **xAI Grok OAuth (SuperGrok Subscription)** in `hermes model`, or run `hermes auth add xai-oauth`. The same OAuth bearer token is automatically reused by direct-to-xAI tools (TTS, image gen, video gen, transcription). See the [xAI Grok OAuth guide](../guides/xai-grok-oauth.md) for the full flow.
|
||||
|
||||
When using xAI as a provider (any base URL containing `x.ai`), Hermes automatically enables prompt caching by sending the `x-grok-conv-id` header with every API request. This routes requests to the same server within a conversation session, allowing xAI's infrastructure to reuse cached system prompts and conversation history.
|
||||
|
||||
No configuration is needed — caching activates automatically when an xAI endpoint is detected and a session ID is available. This reduces latency and cost for multi-turn conversations.
|
||||
|
|
@ -1444,7 +1446,7 @@ fallback_model:
|
|||
|
||||
When activated, the fallback swaps the model and provider mid-session without losing your conversation. The chain is tried entry-by-entry; activation is one-shot per session.
|
||||
|
||||
Supported providers: `openrouter`, `nous`, `openai-codex`, `copilot`, `copilot-acp`, `anthropic`, `gemini`, `google-gemini-cli`, `qwen-oauth`, `huggingface`, `zai`, `kimi-coding`, `kimi-coding-cn`, `minimax`, `minimax-cn`, `minimax-oauth`, `deepseek`, `nvidia`, `xai`, `ollama-cloud`, `bedrock`, `ai-gateway`, `azure-foundry`, `opencode-zen`, `opencode-go`, `kilocode`, `xiaomi`, `arcee`, `gmi`, `stepfun`, `lmstudio`, `alibaba`, `alibaba-coding-plan`, `tencent-tokenhub`, `custom`.
|
||||
Supported providers: `openrouter`, `nous`, `openai-codex`, `copilot`, `copilot-acp`, `anthropic`, `gemini`, `google-gemini-cli`, `qwen-oauth`, `huggingface`, `zai`, `kimi-coding`, `kimi-coding-cn`, `minimax`, `minimax-cn`, `minimax-oauth`, `deepseek`, `nvidia`, `xai`, `xai-oauth`, `ollama-cloud`, `bedrock`, `ai-gateway`, `azure-foundry`, `opencode-zen`, `opencode-go`, `kilocode`, `xiaomi`, `arcee`, `gmi`, `stepfun`, `lmstudio`, `alibaba`, `alibaba-coding-plan`, `tencent-tokenhub`, `custom`.
|
||||
|
||||
:::tip
|
||||
Fallback is configured exclusively through `config.yaml` — or interactively via `hermes fallback`. For full details on when it triggers, how the chain advances, and how it interacts with auxiliary tasks and delegation, see [Fallback Providers](/docs/user-guide/features/fallback-providers).
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue