From b32461f6e864dddcd9c7e0a8976b4e4ca50616db Mon Sep 17 00:00:00 2001 From: Shannon Sands Date: Fri, 8 May 2026 10:24:34 +1000 Subject: [PATCH] fix(auth): send Nous refresh token via header --- hermes_cli/auth.py | 2 +- tests/hermes_cli/test_auth_nous_provider.py | 40 ++++++++++++++++++++- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/hermes_cli/auth.py b/hermes_cli/auth.py index 3fa726d6a7..425ffb6f25 100644 --- a/hermes_cli/auth.py +++ b/hermes_cli/auth.py @@ -3117,10 +3117,10 @@ def _refresh_access_token( ) -> Dict[str, Any]: response = client.post( f"{portal_base_url}/api/oauth/token", + headers={"x-nous-refresh-token": refresh_token}, data={ "grant_type": "refresh_token", "client_id": client_id, - "refresh_token": refresh_token, }, ) diff --git a/tests/hermes_cli/test_auth_nous_provider.py b/tests/hermes_cli/test_auth_nous_provider.py index 136265c7e4..1af26cc9ff 100644 --- a/tests/hermes_cli/test_auth_nous_provider.py +++ b/tests/hermes_cli/test_auth_nous_provider.py @@ -1,7 +1,6 @@ """Regression tests for Nous OAuth refresh + agent-key mint interactions.""" import json -import os from datetime import datetime, timezone from pathlib import Path @@ -862,6 +861,45 @@ def test_refresh_token_reuse_detection_surfaces_actionable_message(): assert exc_info.value.relogin_required is True +def test_refresh_token_exchange_sends_refresh_token_header(): + """Nous refresh tokens must be sent in a header so sandbox proxies can + substitute placeholder credentials without parsing form bodies. + """ + from hermes_cli.auth import _refresh_access_token + + class _FakeResponse: + status_code = 200 + + def json(self): + return {"access_token": "access-2", "refresh_token": "refresh-2"} + + class _FakeClient: + def __init__(self): + self.kwargs = None + + def post(self, *args, **kwargs): + del args + self.kwargs = kwargs + return _FakeResponse() + + client = _FakeClient() + + payload = _refresh_access_token( + client=client, + portal_base_url="https://portal.nousresearch.com", + client_id="hermes-cli", + refresh_token="refresh-1", + ) + + assert payload["access_token"] == "access-2" + assert client.kwargs is not None + assert client.kwargs["headers"]["x-nous-refresh-token"] == "refresh-1" + assert client.kwargs["data"] == { + "grant_type": "refresh_token", + "client_id": "hermes-cli", + } + + def test_refresh_non_reuse_error_keeps_original_description(): """Non-reuse invalid_grant errors must keep their original description untouched.