Skip to content

feat(oauth): add automatic OAuth token refresh for Claude API credentials#1725

Open
Saxin wants to merge 1 commit intoqwibitai:mainfrom
Saxin:feat/oauth-token-refresh
Open

feat(oauth): add automatic OAuth token refresh for Claude API credentials#1725
Saxin wants to merge 1 commit intoqwibitai:mainfrom
Saxin:feat/oauth-token-refresh

Conversation

@Saxin
Copy link
Copy Markdown

@Saxin Saxin commented Apr 10, 2026

Summary

  • Adds src/oauth-token.ts with ensureFreshOAuthToken() — refreshes Claude OAuth tokens from ~/.claude/.credentials.json before they expire
  • Without this, long idle periods cause containers to receive 401 Invalid authentication credentials
  • Wired up in two places: on every container launch (on-demand) and via a background 30-min interval (prevents expiry during inactivity)

Details

The platform.claude.com/v1/oauth/token endpoint requires client_id and scope fields in addition to grant_type + refresh_token — omitting them returns 400 Invalid request format. The rotating refresh_token from the response is also written back to credentials.json.

Configuration via .env:

  • ONECLI_OAUTH_SECRET_ID — OneCLI secret ID to sync the fresh token into (optional; skip if not using OneCLI)

Files changed

  • src/oauth-token.ts (new) — token refresh logic
  • src/config.tsONECLI_OAUTH_SECRET_ID and ONECLI_BIN exports
  • src/container-runner.ts — call ensureFreshOAuthToken before each container launch
  • src/index.ts — background 30-min refresh interval

Test plan

  • Verified on live instance — bot running since 2026-04-09 with zero 401 errors after this fix
  • Unit tests for ensureFreshOAuthToken (mocking https.request and fs)

🤖 Generated with Claude Code

…ials

NanoClaw uses Claude's OAuth tokens (sk-ant-oat01-...) from
~/.claude/.credentials.json to authenticate containers. Without refresh,
tokens expire and containers receive 401 errors.

This adds src/oauth-token.ts with ensureFreshOAuthToken():
- Reads the OAuth token from ~/.claude/.credentials.json
- Calls platform.claude.com/v1/oauth/token with grant_type=refresh_token,
  client_id, and scope fields (all required by the endpoint)
- Writes the new access_token and rotating refresh_token back to
  credentials.json
- Syncs the fresh token into an OneCLI secret (ONECLI_OAUTH_SECRET_ID)
  so containers always receive a valid credential

Wired up in two places:
- container-runner.ts: refresh on every container launch (on-demand)
- index.ts: background setInterval every 30 min (prevents expiry during
  inactivity when no containers are launched for a long time)

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
pakkeiC pushed a commit to pakkeiC/nanoclaw that referenced this pull request Apr 13, 2026
…ials

Port of upstream PR qwibitai#1725. NanoClaw uses Claude OAuth tokens from
~/.claude/.credentials.json. Without refresh, tokens expire and containers
receive 401 authentication errors.

Changes:
- src/oauth-token.ts: new ensureFreshOAuthToken() — reads credentials.json,
  calls platform.claude.com/v1/oauth/token with refresh_token grant,
  writes new access_token back to credentials.json, optionally syncs to
  OneCLI secret (ONECLI_OAUTH_SECRET_ID) for future OneCLI migration
- src/credential-proxy.ts: read OAuth token dynamically from credentials.json
  on each proxied request instead of once at startup — prevents stale .env
  tokens from causing 401s
- src/container-runner.ts: call ensureFreshOAuthToken() before each container
  launch (on-demand refresh)
- src/index.ts: background setInterval every 30 min (prevents expiry during
  inactivity when no containers are launched)
- src/config.ts: add ONECLI_BIN and ONECLI_OAUTH_SECRET_ID constants
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant