test+docs(oauth): pin manual-paste semantics and document browser-only path (#26923)
Tests (``tests/hermes_cli/test_auth_manual_paste.py``): * 9 parametrised + scalar cases for ``_is_remote_session`` covering the new Cloud Shell / Codespaces / Gitpod / Replit / StackBlitz env vars (plus the existing SSH ones). * 9 cases for ``_parse_pasted_callback`` covering every paste form (full URL, https URL with extra params, bare ``?code=...``, bare ``code=...`` fragment, bare opaque value, error+description, empty, whitespace-only, malformed URL). * 3 cases for ``_prompt_manual_callback_paste`` (happy path, EOF, Ctrl-C). * 3 end-to-end ``_xai_oauth_loopback_login(manual_paste=True)`` cases: the HTTP server MUST NOT be started (asserted via a callable that raises if invoked), wrong state still rejected with ``xai_state_mismatch`` (no CSRF bypass), and empty paste surfaces ``xai_code_missing``. * SSH-hint mention test ensures the ``--manual-paste`` instruction is printed in the remote-session hint. Docs: * ``oauth-over-ssh.md`` — new "Browser-only remote (Cloud Shell / Codespaces / EC2 Instance Connect)" section with the ``--manual-paste`` recipe, plus a TL;DR note for the new flag. * ``xai-grok-oauth.md`` — short subsection pointing at the same recipe and the OAuth-over-SSH guide anchor.
This commit is contained in:
@@ -10,7 +10,7 @@ Some Hermes providers — currently **xAI Grok OAuth** and **Spotify** — use a
|
||||
|
||||
This works perfectly when Hermes and your browser are on the same machine. It breaks the moment they aren't: your laptop's browser tries to reach `127.0.0.1` on **your laptop**, but the listener is bound to `127.0.0.1` on **the remote server**.
|
||||
|
||||
The fix is a one-line SSH local-forward.
|
||||
The fix is a one-line SSH local-forward — **or**, when you don't have a real SSH client (GCP Cloud Shell, GitHub Codespaces, EC2 Instance Connect, Gitpod, browser-based web IDEs), the new `--manual-paste` flag introduced in [#26923](https://github.com/NousResearch/hermes-agent/issues/26923).
|
||||
|
||||
## TL;DR
|
||||
|
||||
@@ -27,6 +27,23 @@ hermes auth add xai-oauth --no-browser
|
||||
|
||||
Port `56121` is what xAI OAuth uses. For Spotify, replace it with `43827`. Hermes prints the exact port it bound to on the `Waiting for callback on ...` line — copy it from there.
|
||||
|
||||
## Browser-only remote (Cloud Shell / Codespaces / EC2 Instance Connect)
|
||||
|
||||
If you don't have a regular SSH client — for example because you're running Hermes inside GCP Cloud Shell, GitHub Codespaces, AWS EC2 Instance Connect, Gitpod, or another browser-based console — the SSH tunnel above isn't available. Use `--manual-paste` instead:
|
||||
|
||||
```bash
|
||||
hermes auth add xai-oauth --manual-paste
|
||||
# → Hermes prints an authorize URL. Open it in a browser on your laptop.
|
||||
# → Approve in the browser. The redirect to 127.0.0.1:56121/callback fails
|
||||
# to load — that's expected.
|
||||
# → Copy the FULL URL from the failed page's address bar.
|
||||
# → Paste it back into the terminal at the "Callback URL:" prompt.
|
||||
```
|
||||
|
||||
The same flag works on `hermes model --manual-paste` for the integrated model picker. A bare `?code=...&state=...` query fragment is accepted too if you don't want to paste the whole URL.
|
||||
|
||||
Hermes uses the **same PKCE verifier, state and nonce** for both paths, so the upstream OAuth flow is byte-identical — `--manual-paste` is purely a transport change for the callback hop and is not a security downgrade.
|
||||
|
||||
## Which Providers Need This
|
||||
|
||||
| Provider | Loopback port | Tunnel needed? |
|
||||
|
||||
@@ -80,6 +80,18 @@ Through a jump box / bastion: add `-J jump-user@jump-host`.
|
||||
|
||||
See [OAuth over SSH / Remote Hosts](./oauth-over-ssh.md) for the full step-by-step, including ProxyJump chains, mosh/tmux, and ControlMaster gotchas.
|
||||
|
||||
### Browser-only remotes (Cloud Shell, Codespaces, EC2 Instance Connect)
|
||||
|
||||
If you don't have a regular SSH client (e.g. you're running Hermes inside GCP Cloud Shell, GitHub Codespaces, AWS EC2 Instance Connect, Gitpod, or another browser-based console), the `ssh -L` recipe above isn't available. Use `--manual-paste` instead — Hermes skips the loopback listener and lets you paste the failed callback URL straight from your browser:
|
||||
|
||||
```bash
|
||||
hermes auth add xai-oauth --manual-paste
|
||||
# Or via the model picker:
|
||||
hermes model --manual-paste
|
||||
```
|
||||
|
||||
See [OAuth over SSH / Remote Hosts](./oauth-over-ssh.md#browser-only-remote-cloud-shell--codespaces--ec2-instance-connect) for the full walkthrough. Regression fix for [#26923](https://github.com/NousResearch/hermes-agent/issues/26923).
|
||||
|
||||
## How the Login Works
|
||||
|
||||
1. Hermes opens your browser to `accounts.x.ai`.
|
||||
|
||||
Reference in New Issue
Block a user