Remote control bridge should auto-refresh OAuth token before expiry
Summary
The remote control bridge silently dies when the OAuth token expires mid-session. The heartbeat fails with a 401 and the session becomes unrecoverable — but the bridge keeps polling as if nothing happened, giving no indication to the user that the session is dead.
Steps to reproduce
- Start a remote control bridge:
claude remote-control --spawn same-dir --verbose - Connect from a mobile device and use the session normally
- Wait ~5 hours
- Heartbeat fails with:
Authentication failed (401): Token expired. Remote Control is only available with claude.ai subscriptions. - Session is dead — bridge continues polling but no work comes in
Expected behavior
The bridge should proactively refresh the OAuth token before it expires, keeping the session alive indefinitely (or until the user disconnects).
Evidence that token refresh already works
The bridge does successfully refresh the token in other code paths. During shutdown, the stop-work call gets a 401, refreshes the token, and retries successfully:
[bridge:api] StopWork: 401 received, attempting token refresh
[bridge:api] StopWork: Token refreshed, retrying request
[bridge:api] POST .../work/.../stop -> 200
So the refresh capability exists — it is just not wired into the heartbeat loop.
Why this matters
The primary use case for remote control is controlling Claude Code from a phone while away from the laptop. If the token expires mid-session, there is no way to recover — the user cannot run /login from their phone since the bridge runs on the laptop. The session silently dies and the user loses access until they are physically back at the machine.
Suggested fix
- Proactively refresh the OAuth token before TTL expiry (e.g., at 80% of TTL)
- Or at minimum: catch 401 on heartbeat, refresh the token, and retry — same pattern already used in the stop-work path
- If refresh fails, surface a clear error to the connected client rather than silently continuing to poll
Environment
- macOS (Apple Silicon)
- Claude Code CLI (latest as of Mar 2026)
- Session duration before failure: ~5h 14m
- Bridge continued polling for ~1.5h after token death before manual SIGINT
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗