mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-27 11:22:03 +00:00
fix(anthropic): use platform.claude.com for OAuth token exchange
Anthropic migrated the OAuth token endpoint from console.anthropic.com/v1/oauth/token (now returns HTTP 404) to platform.claude.com/v1/oauth/token. The token *refresh* path already iterated both hosts, but the two initial code-exchange call sites were hardcoded to the dead console host, so every new Claude OAuth login failed with 'Token exchange failed: HTTP Error 404: Not Found' and saved no credentials. Fix the whole bug class: - Add _OAUTH_TOKEN_URLS [platform.claude.com, console.anthropic.com] in agent/anthropic_adapter.py; _OAUTH_TOKEN_URL now points at the live host for backward-compat with existing imports. - run_hermes_oauth_login_pure() (CLI flow) iterates the list, first success wins, mirroring the refresh path. - hermes_cli/web_server.py (desktop dashboard flow) imports the list and iterates it too, so the GUI login path is fixed identically. Probe: console.anthropic.com/v1/oauth/token -> HTTP 404 (gone), platform.claude.com/v1/oauth/token -> HTTP 400 (alive). Verified a real Claude MAX OAuth login now succeeds end-to-end.
This commit is contained in:
parent
be78fbd70e
commit
2ee6449fe5
2 changed files with 60 additions and 26 deletions
|
|
@ -1297,7 +1297,15 @@ def run_oauth_setup_token() -> Optional[str]:
|
|||
# Stores credentials in ~/.hermes/.anthropic_oauth.json (our own file).
|
||||
|
||||
_OAUTH_CLIENT_ID = "9d1c250a-e61b-44d9-88ed-5944d1962f5e"
|
||||
_OAUTH_TOKEN_URL = "https://console.anthropic.com/v1/oauth/token"
|
||||
# Anthropic migrated the OAuth token endpoint to platform.claude.com;
|
||||
# console.anthropic.com now 404s. Callers should iterate _OAUTH_TOKEN_URLS
|
||||
# (new host first, console fallback). _OAUTH_TOKEN_URL is kept as the primary
|
||||
# for backward compatibility with existing imports and now points at the live host.
|
||||
_OAUTH_TOKEN_URLS = [
|
||||
"https://platform.claude.com/v1/oauth/token",
|
||||
"https://console.anthropic.com/v1/oauth/token",
|
||||
]
|
||||
_OAUTH_TOKEN_URL = _OAUTH_TOKEN_URLS[0]
|
||||
_OAUTH_REDIRECT_URI = "https://console.anthropic.com/oauth/code/callback"
|
||||
_OAUTH_SCOPES = "org:create_api_key user:profile user:inference"
|
||||
_HERMES_OAUTH_FILE = get_hermes_home() / ".anthropic_oauth.json"
|
||||
|
|
@ -1395,18 +1403,34 @@ def run_hermes_oauth_login_pure() -> Optional[Dict[str, Any]]:
|
|||
"code_verifier": verifier,
|
||||
}).encode()
|
||||
|
||||
req = urllib.request.Request(
|
||||
_OAUTH_TOKEN_URL,
|
||||
data=exchange_data,
|
||||
headers={
|
||||
"Content-Type": "application/json",
|
||||
"User-Agent": f"claude-cli/{_get_claude_code_version()} (external, cli)",
|
||||
},
|
||||
method="POST",
|
||||
)
|
||||
# Anthropic migrated the OAuth token endpoint to platform.claude.com;
|
||||
# console.anthropic.com now 404s. Try the new host first, then fall
|
||||
# back to console for older deployments (mirrors the refresh path).
|
||||
result = None
|
||||
last_error = None
|
||||
for endpoint in _OAUTH_TOKEN_URLS:
|
||||
req = urllib.request.Request(
|
||||
endpoint,
|
||||
data=exchange_data,
|
||||
headers={
|
||||
"Content-Type": "application/json",
|
||||
"User-Agent": f"claude-cli/{_get_claude_code_version()} (external, cli)",
|
||||
},
|
||||
method="POST",
|
||||
)
|
||||
try:
|
||||
with urllib.request.urlopen(req, timeout=15) as resp:
|
||||
result = json.loads(resp.read().decode())
|
||||
break
|
||||
except Exception as exc:
|
||||
last_error = exc
|
||||
logger.debug("Anthropic token exchange failed at %s: %s", endpoint, exc)
|
||||
continue
|
||||
|
||||
with urllib.request.urlopen(req, timeout=15) as resp:
|
||||
result = json.loads(resp.read().decode())
|
||||
if result is None:
|
||||
raise last_error if last_error is not None else ValueError(
|
||||
"Anthropic token exchange failed"
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"Token exchange failed: {e}")
|
||||
return None
|
||||
|
|
|
|||
|
|
@ -6123,6 +6123,7 @@ try:
|
|||
from agent.anthropic_adapter import (
|
||||
_OAUTH_CLIENT_ID as _ANTHROPIC_OAUTH_CLIENT_ID,
|
||||
_OAUTH_TOKEN_URL as _ANTHROPIC_OAUTH_TOKEN_URL,
|
||||
_OAUTH_TOKEN_URLS as _ANTHROPIC_OAUTH_TOKEN_URLS,
|
||||
_OAUTH_REDIRECT_URI as _ANTHROPIC_OAUTH_REDIRECT_URI,
|
||||
_OAUTH_SCOPES as _ANTHROPIC_OAUTH_SCOPES,
|
||||
_generate_pkce as _generate_pkce_pair,
|
||||
|
|
@ -6311,22 +6312,31 @@ def _submit_anthropic_pkce(
|
|||
"redirect_uri": _ANTHROPIC_OAUTH_REDIRECT_URI,
|
||||
"code_verifier": sess["verifier"],
|
||||
}).encode()
|
||||
req = urllib.request.Request(
|
||||
_ANTHROPIC_OAUTH_TOKEN_URL,
|
||||
data=exchange_data,
|
||||
headers={
|
||||
"Content-Type": "application/json",
|
||||
"User-Agent": "hermes-dashboard/1.0",
|
||||
},
|
||||
method="POST",
|
||||
)
|
||||
try:
|
||||
with urllib.request.urlopen(req, timeout=20) as resp:
|
||||
result = json.loads(resp.read().decode())
|
||||
except Exception as e:
|
||||
# Anthropic migrated the OAuth token endpoint to platform.claude.com;
|
||||
# console.anthropic.com now 404s. Try the new host first, then fall back.
|
||||
result = None
|
||||
last_exc = None
|
||||
for _endpoint in _ANTHROPIC_OAUTH_TOKEN_URLS:
|
||||
req = urllib.request.Request(
|
||||
_endpoint,
|
||||
data=exchange_data,
|
||||
headers={
|
||||
"Content-Type": "application/json",
|
||||
"User-Agent": "hermes-dashboard/1.0",
|
||||
},
|
||||
method="POST",
|
||||
)
|
||||
try:
|
||||
with urllib.request.urlopen(req, timeout=20) as resp:
|
||||
result = json.loads(resp.read().decode())
|
||||
break
|
||||
except Exception as e:
|
||||
last_exc = e
|
||||
continue
|
||||
if result is None:
|
||||
with _oauth_sessions_lock:
|
||||
sess["status"] = "error"
|
||||
sess["error_message"] = f"Token exchange failed: {e}"
|
||||
sess["error_message"] = f"Token exchange failed: {last_exc}"
|
||||
return {"ok": False, "status": "error", "message": sess["error_message"]}
|
||||
|
||||
access_token = result.get("access_token", "")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue