VS Code extension: in-app 'Log in' fails with 400 on claude_oauth_callback after refresh-token expiry
Description
The VS Code extension's built-in "Log in" flow failed to complete after a mid-session OAuth refresh-token expiry, with no automatic retry or clear recovery path. I had to fall back to logging in from a separate terminal via the claude CLI's own /login, which worked and unblocked the extension once its credentials file was updated.
Environment
- Claude Code VS Code extension, bundled native binary version 2.1.229 (a newer 2.1.229→2.1.231 CLI self-update had already landed and was cached by VS Code, but not yet hot-swapped into the running extension host — window had not been reloaded/restarted)
- WSL2 (Ubuntu) remote, VS Code Desktop connecting via Remote-WSL
cc_entrypoint=claude-vscode
Timeline (from the extension's own Claude VSCode.log)
08:01:20— Mid-session API call fails:OAuth refresh token is no longer valid; run /login to re-authenticate. (Expected/normal — refresh tokens expire.)08:01:29— I click "Log in" in the extension's sidebar UI ({"type":"login","method":"claudeai"}).08:02:33— I submit the one-time code shown after completing the browser login ({"type":"submit_oauth_code","code":"..."}), about 64 seconds after starting the flow — well within any normal code-expiry window.08:02:34— The redemption fails:
````
[INFO] claude_authenticate flow ended: AxiosError: Request failed with status code 400
[error] Error processing client request: Error: Request failed with status code 400
[warning] claude_oauth_callback rejected: Error: Request failed with status code 400
- No further retry happens automatically. By
08:07:50the extension is still reportingAuth error: No API key available. - I opened a separate terminal, ran the
claudeCLI directly, and used its own/logincommand — a different code path from the extension's webview login button — which completed successfully.~/.claude/.credentials.jsonwas rewritten at08:08:49, and the extension picked up the refreshed credentials from there without needing a window reload.
Expected behavior
The extension's own in-UI login flow should succeed under the same conditions the CLI's /login succeeds under (same account, same machine, ~1 minute apart), or at minimum should surface a clear, actionable error and offer an automatic retry instead of silently failing at claude_oauth_callback and leaving the user stuck with no working auth path inside VS Code.
Actual behavior
The extension's login button's OAuth code redemption (claude_oauth_callback) returns an unexplained HTTP 400 and the flow just ends, with the UI left in a state that looks like nothing happened. The only way to recover was to leave VS Code entirely and re-authenticate from a terminal.
Impact
This turned a routine, expected token expiry into a multi-step, confusing recovery (browser login → email verification code → terminal /login → manual key entry) that took several minutes and required leaving the editor entirely — a significantly worse experience than the extension's own login button is presumably meant to provide.