Compare commits

...

1 Commits

Author SHA1 Message Date
Teknium
1e36185b70 fix(auth): kimi-coding pool base_url seeding + PKCE endpoint fallback
1. credential_pool._seed_from_env() now calls _resolve_kimi_base_url()
   for kimi-coding provider, matching the runtime resolver logic.
   Previously, sk-kimi- prefixed keys were seeded with the default
   moonshot.ai URL, causing 401 on first request. Fixes #5561.

2. Hermes-native PKCE OAuth login (run_hermes_oauth_login_pure) now
   tries platform.claude.com first with console.anthropic.com fallback,
   consistent with refresh_anthropic_oauth_pure(). The old _OAUTH_TOKEN_URL
   constant hardcoded console.anthropic.com only.
2026-04-07 00:00:34 -07:00
2 changed files with 31 additions and 13 deletions

View File

@@ -591,7 +591,10 @@ def run_oauth_setup_token() -> Optional[str]:
# Stores credentials in ~/.hermes/.anthropic_oauth.json (our own file). # Stores credentials in ~/.hermes/.anthropic_oauth.json (our own file).
_OAUTH_CLIENT_ID = "9d1c250a-e61b-44d9-88ed-5944d1962f5e" _OAUTH_CLIENT_ID = "9d1c250a-e61b-44d9-88ed-5944d1962f5e"
_OAUTH_TOKEN_URL = "https://console.anthropic.com/v1/oauth/token" _OAUTH_TOKEN_URLS = [
"https://platform.claude.com/v1/oauth/token",
"https://console.anthropic.com/v1/oauth/token",
]
_OAUTH_REDIRECT_URI = "https://console.anthropic.com/oauth/code/callback" _OAUTH_REDIRECT_URI = "https://console.anthropic.com/oauth/code/callback"
_OAUTH_SCOPES = "org:create_api_key user:profile user:inference" _OAUTH_SCOPES = "org:create_api_key user:profile user:inference"
_HERMES_OAUTH_FILE = get_hermes_home() / ".anthropic_oauth.json" _HERMES_OAUTH_FILE = get_hermes_home() / ".anthropic_oauth.json"
@@ -676,8 +679,11 @@ def run_hermes_oauth_login_pure() -> Optional[Dict[str, Any]]:
"code_verifier": verifier, "code_verifier": verifier,
}).encode() }).encode()
result = None
last_error = None
for endpoint in _OAUTH_TOKEN_URLS:
req = urllib.request.Request( req = urllib.request.Request(
_OAUTH_TOKEN_URL, endpoint,
data=exchange_data, data=exchange_data,
headers={ headers={
"Content-Type": "application/json", "Content-Type": "application/json",
@@ -685,9 +691,17 @@ def run_hermes_oauth_login_pure() -> Optional[Dict[str, Any]]:
}, },
method="POST", method="POST",
) )
try:
with urllib.request.urlopen(req, timeout=15) as resp: with urllib.request.urlopen(req, timeout=15) as resp:
result = json.loads(resp.read().decode()) result = json.loads(resp.read().decode())
break
except Exception as exc:
logger.debug("Token exchange failed at %s: %s", endpoint, exc)
last_error = exc
continue
if result is None:
raise last_error or ValueError("Token exchange failed on all endpoints")
except Exception as e: except Exception as e:
print(f"Token exchange failed: {e}") print(f"Token exchange failed: {e}")
return None return None

View File

@@ -27,6 +27,7 @@ from hermes_cli.auth import (
_is_expiring, _is_expiring,
_load_auth_store, _load_auth_store,
_load_provider_state, _load_provider_state,
_resolve_kimi_base_url,
read_credential_pool, read_credential_pool,
write_credential_pool, write_credential_pool,
) )
@@ -1085,6 +1086,9 @@ def _seed_from_env(provider: str, entries: List[PooledCredential]) -> Tuple[bool
source = f"env:{env_var}" source = f"env:{env_var}"
active_sources.add(source) active_sources.add(source)
auth_type = AUTH_TYPE_OAUTH if provider == "anthropic" and not token.startswith("sk-ant-api") else AUTH_TYPE_API_KEY auth_type = AUTH_TYPE_OAUTH if provider == "anthropic" and not token.startswith("sk-ant-api") else AUTH_TYPE_API_KEY
if provider == "kimi-coding":
base_url = _resolve_kimi_base_url(token, pconfig.inference_base_url, env_url)
else:
base_url = env_url or pconfig.inference_base_url base_url = env_url or pconfig.inference_base_url
changed |= _upsert_entry( changed |= _upsert_entry(
entries, entries,