Skip to content

feat(cli): Allow pasting a long-lived OAuth setup token#253

Open
jwaldrip wants to merge 1 commit into
hamed-elfayome:mainfrom
jwaldrip:claude/cli-oauth-token-config-4QKuN
Open

feat(cli): Allow pasting a long-lived OAuth setup token#253
jwaldrip wants to merge 1 commit into
hamed-elfayome:mainfrom
jwaldrip:claude/cli-oauth-token-config-4QKuN

Conversation

@jwaldrip

Copy link
Copy Markdown

Description

Adds a "Paste an OAuth Setup Token" section to the CLI Account settings view so users can configure their profile with a long-lived token generated by claude setup-token instead of relying on a potentially-expired web sync flow from Claude Code's keychain. This is useful when a user's Claude Code session is dead/expired and re-running the OAuth web flow isn't viable (CI environments, remote machines, stale sessions).

The token is wrapped in a minimal claudeAiOauth JSON envelope and stored in the active profile's cliCredentialsJSON; downstream usage extraction (ClaudeAPIService.getAuthentication, Profile.hasValidCLIOAuth) consumes it through the existing helpers — no new code paths in the request layer. Long-lived setup tokens have no expiresAt field, which intentionally makes isTokenExpired return false ("no expiry info = assume valid"), matching the lifecycle of claude setup-token output.

Changes

  • ClaudeCodeSyncService.saveManualOAuthToken(_:profileId:) — wraps a trimmed token in {"claudeAiOauth":{"accessToken":"…","subscriptionType":"manual","scopes":["user:inference","user:profile"]}}, writes it to the profile, and sets hasCliAccount/cliAccountSyncedAt. Adds a new ClaudeCodeError.invalidToken case for empty input.
  • CLIAccountView — new SettingsSectionCard containing a collapsible DisclosureGroup with a monospaced TextField (sk-ant-oat01-… placeholder), inline error display, and a Save button. Reuses existing DesignTokens (inputBackground, cardBorder, Radius.small, etc.) for visual consistency with the manual session-key entry in PersonalUsageView.
  • Localization — 7 new keys (cli.manual_token_title, cli.manual_token_subtitle, cli.manual_token_disclosure, cli.manual_token_help, cli.manual_token_placeholder, cli.manual_token_save, cli.manual_token_empty_error) translated into all 13 .lproj files (en, de, es, fr, it, ja, ko, pt-BR, pt, tr, uk, zh-Hant, zh-ch).

No changes to ClaudeAPIService, Profile model, or the storage layer — the new token flows through the existing CLI OAuth fallback path in getAuthentication() (priority 2, ahead of system Keychain lookup).

Screenshots / Screen Recordings

⚠️ I wasn't able to run the app from this environment — please attach a screenshot of the new "Paste an OAuth Setup Token" card on the CLI Account settings page (both collapsed and expanded states) before requesting review.

Checklist

  • I have tested these changes on a running build (needs verification on macOS)
  • I have attached screenshots/recordings for any visual changes (see note above)
  • I have not introduced App Group or grouped Keychain usage — token is stored in the profile via the existing ProfileStore (standard UserDefaults), no new Keychain access
  • I have added localization keys for any new user-facing strings — 7 keys added to all 13 supported languages; scripts/validate_localizations.sh confirms no new mismatches were introduced

Adds a "Paste an OAuth Setup Token" section to the CLI Account
settings view so users can configure their profile with a token
generated by `claude setup-token` instead of relying on a
potentially-expired web sync flow.

The token is wrapped in a minimal claudeAiOauth JSON envelope and
stored in the active profile's cliCredentialsJSON; downstream usage
extraction (ClaudeAPIService.getAuthentication, hasValidCLIOAuth)
consumes it via the existing helpers. Long-lived setup tokens have
no expiresAt field, which intentionally makes isTokenExpired return
false ("no expiry info = assume valid").
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.

2 participants