fix: Anthropic OAuth token refresh URL migration + WSL credential path detection#3237
fix: Anthropic OAuth token refresh URL migration + WSL credential path detection#3237LucidPaths wants to merge 1 commit into
Conversation
Anthropic migrated their developer console from console.anthropic.com to platform.claude.com. The old domain now 302-redirects to the new one. This broke: 1. OAuth token refresh (_refresh_oauth_token) — the token exchange endpoint at console.anthropic.com/v1/oauth/token no longer works directly 2. Display URLs pointing users to console.anthropic.com/settings/keys Additionally, on WSL (Windows Subsystem for Linux), Claude Code runs on the Windows host and writes credentials to the Windows user profile (C:\Users\<name>\.claude\.credentials.json), but Hermes reads from Path.home() which resolves to /home/<user>/ on WSL — a different filesystem. This means read_claude_code_credentials() always returns None on WSL. Changes: - Update OAuth token refresh URL to platform.claude.com/v1/oauth/token - Update 3 display URLs in setup.py, main.py, run_agent.py - Add _is_wsl() detection via /proc/version - Add _wsl_windows_credential_path() to resolve Windows-side credential file via cmd.exe %USERPROFILE% with /mnt/c/Users fallback - read_claude_code_credentials() now checks both native and WSL paths - Handle non-UTF-8 cmd.exe output (e.g. German locale) gracefully - Disable WSL detection in test suite via conftest autouse fixture Tested: 77/77 tests pass in test_anthropic_adapter.py
|
Thanks for the thorough investigation @LucidPaths! A few notes on the current state: OAuth refresh URL (Bug 1) — This was already fixed in PR #3246. Main already has a dual-endpoint approach that tries Display URLs — Good catch, these are still stale. We'll merge those updates directly. WSL credential detection (Bug 2) — We're going to pass on this one. The complexity (spawning Closing this PR since the core issue is already resolved and we'll handle the display URLs separately. Thanks for the contribution! |
Anthropic migrated their developer console from console.anthropic.com to platform.claude.com. Three user-facing display URLs were still pointing to the old domain. Spotted by @LucidPaths in PR #3237.
Anthropic migrated their developer console from console.anthropic.com to platform.claude.com. Two user-facing display URLs were still pointing to the old domain: - hermes_cli/main.py — API key prompt in the Anthropic model flow - run_agent.py — 401 troubleshooting output The OAuth token refresh endpoint was already migrated in PR #3246 (with fallback). Spotted by @LucidPaths in PR #3237. (Salvage of #3758 — dropped the setup.py hunk since that section was refactored away and no longer contains the stale URL.)
Anthropic migrated their developer console from console.anthropic.com to platform.claude.com. Two user-facing display URLs were still pointing to the old domain: - hermes_cli/main.py — API key prompt in the Anthropic model flow - run_agent.py — 401 troubleshooting output The OAuth token refresh endpoint was already migrated in PR #3246 (with fallback). Spotted by @LucidPaths in PR #3237. (Salvage of #3758 — dropped the setup.py hunk since that section was refactored away and no longer contains the stale URL.)
Anthropic migrated their developer console from console.anthropic.com to platform.claude.com. Three user-facing display URLs were still pointing to the old domain. Spotted by @LucidPaths in PR NousResearch#3237.
Anthropic migrated their developer console from console.anthropic.com to platform.claude.com. Two user-facing display URLs were still pointing to the old domain: - hermes_cli/main.py — API key prompt in the Anthropic model flow - run_agent.py — 401 troubleshooting output The OAuth token refresh endpoint was already migrated in PR NousResearch#3246 (with fallback). Spotted by @LucidPaths in PR NousResearch#3237. (Salvage of NousResearch#3758 — dropped the setup.py hunk since that section was refactored away and no longer contains the stale URL.)
Anthropic migrated their developer console from console.anthropic.com to platform.claude.com. Two user-facing display URLs were still pointing to the old domain: - hermes_cli/main.py — API key prompt in the Anthropic model flow - run_agent.py — 401 troubleshooting output The OAuth token refresh endpoint was already migrated in PR NousResearch#3246 (with fallback). Spotted by @LucidPaths in PR NousResearch#3237. (Salvage of NousResearch#3758 — dropped the setup.py hunk since that section was refactored away and no longer contains the stale URL.)
Anthropic migrated their developer console from console.anthropic.com to platform.claude.com. Two user-facing display URLs were still pointing to the old domain: - hermes_cli/main.py — API key prompt in the Anthropic model flow - run_agent.py — 401 troubleshooting output The OAuth token refresh endpoint was already migrated in PR NousResearch#3246 (with fallback). Spotted by @LucidPaths in PR NousResearch#3237. (Salvage of NousResearch#3758 — dropped the setup.py hunk since that section was refactored away and no longer contains the stale URL.)
Anthropic migrated their developer console from console.anthropic.com to platform.claude.com. Three user-facing display URLs were still pointing to the old domain. Spotted by @LucidPaths in PR NousResearch#3237.
Anthropic migrated their developer console from console.anthropic.com to platform.claude.com. Two user-facing display URLs were still pointing to the old domain: - hermes_cli/main.py — API key prompt in the Anthropic model flow - run_agent.py — 401 troubleshooting output The OAuth token refresh endpoint was already migrated in PR NousResearch#3246 (with fallback). Spotted by @LucidPaths in PR NousResearch#3237. (Salvage of NousResearch#3758 — dropped the setup.py hunk since that section was refactored away and no longer contains the stale URL.)
Anthropic migrated their developer console from console.anthropic.com to platform.claude.com. Two user-facing display URLs were still pointing to the old domain: - hermes_cli/main.py — API key prompt in the Anthropic model flow - run_agent.py — 401 troubleshooting output The OAuth token refresh endpoint was already migrated in PR NousResearch#3246 (with fallback). Spotted by @LucidPaths in PR NousResearch#3237. (Salvage of NousResearch#3758 — dropped the setup.py hunk since that section was refactored away and no longer contains the stale URL.)
Summary
Anthropic migrated their developer console from
console.anthropic.comtoplatform.claude.com. The old domain now 302-redirects. This breaks OAuth token refresh and leaves display URLs stale. Additionally, on WSL,read_claude_code_credentials()can never find credentials because Claude Code on Windows writes to a different filesystem than WSL'sPath.home().Bug 1: Stale OAuth Token Refresh URL
_refresh_oauth_token()POSTs tohttps://console.anthropic.com/v1/oauth/token(line 233). Anthropic's token endpoint now lives athttps://platform.claude.com/v1/oauth/token. The 302 redirect breaks the token exchange because the refresh request fails when followed through a redirect.Impact: Every user's OAuth token refresh silently fails once their initial token expires. This is a ticking time bomb — works until the first expiry, then auth is dead until the user manually re-authenticates.
Fix: Update the URL to
platform.claude.com.Evidence: Claude Code v2.1.84's own source (
cli.js) usesplatform.claude.comfor all OAuth endpoints. Manual token exchange against the old endpoint returnsinvalid_grant.Bug 2: WSL Cannot Find Claude Code Credentials
read_claude_code_credentials()reads fromPath.home() / ".claude" / ".credentials.json". On WSL:/home/<user>/(Linux filesystem)/mnt/c/Users/<user>/(mounted Windows filesystem)Claude Code (running on Windows) writes credentials to
C:\Users\<user>\.claude\.credentials.json. WSL'sPath.home()resolves to/home/<user>/where no.credentials.jsonexists. Result:read_claude_code_credentials()always returnsNoneon WSL.Impact: All WSL users who run Claude Code on Windows cannot use the native Anthropic provider — credentials are never found.
Fix: Add WSL detection via
/proc/versionand resolve the Windows-side credential path viacmd.exe %USERPROFILE%with a/mnt/c/Users/enumeration fallback.read_claude_code_credentials()now checks both native Linux and WSL-mounted Windows paths.Additional: Display URL Updates
Three user-facing messages in
setup.py,main.py, andrun_agent.pypoint users toconsole.anthropic.com/settings/keys— updated toplatform.claude.com/settings/keys.Changes
agent/anthropic_adapter.pyconsole.anthropic.com→platform.claude.comagent/anthropic_adapter.py_is_wsl(),_wsl_windows_credential_path(),_get_credential_paths()agent/anthropic_adapter.pyread_claude_code_credentials()iterates candidate pathshermes_cli/setup.pyhermes_cli/main.pyrun_agent.pytests/conftest.pyTesting
test_anthropic_adapter.pycmd.exeoutput (German locale) handled gracefully witherrors='replace'Context: Claude 4 Models + OAuth
During debugging, we also discovered that Claude 4+ models (Sonnet 4, Opus 4, Opus 4.6) require the Claude Code system prompt prefix (
"You are Claude Code, Anthropic's official CLI for Claude.") when authenticating via OAuth tokens. Without it, the API returns a bare400 {"error": {"message": "Error"}}with no details. This is already handled correctly bybuild_anthropic_kwargs()whenis_oauth=True— but the OAuth path was never reached because of Bugs 1 and 2, making it appear broken.Claude 3 models (Haiku 3, Haiku 4.5) work without the prefix. This is an Anthropic-side behavior that ideally should return a descriptive error.