Skip to content

Improve Claude setup-token OAuth usage and API fallback#133

Merged
hanrw merged 1 commit intotddworks:mainfrom
brendandebeasi:feat/setup-token-support
Feb 26, 2026
Merged

Improve Claude setup-token OAuth usage and API fallback#133
hanrw merged 1 commit intotddworks:mainfrom
brendandebeasi:feat/setup-token-support

Conversation

@brendandebeasi
Copy link
Collaborator

@brendandebeasi brendandebeasi commented Feb 26, 2026

Summary

  • add robust support for CLAUDE_CODE_OAUTH_TOKEN setup tokens (including whitespace/newline normalization) so long-lived local OAuth tokens are accepted reliably
  • improve Claude refresh behavior by falling back between CLI and API probes, allowing sub-limit quotas to load from OAuth API when /usage parsing fails
  • add acceptance and infrastructure regression tests for setup-token auth headers, credential loading, and probe-mode fallback behavior

Verification

  • tuist test Infrastructure -- -only-testing:InfrastructureTests/ClaudeCredentialLoaderTests
  • tuist test AcceptanceTests -- -only-testing:AcceptanceTests/ClaudeConfigSpec
  • tuist test Domain -- -only-testing:DomainTests/AIProviderProtocolTests
  • tuist build

Summary by CodeRabbit

  • Bug Fixes

    • Fixed credential handling by trimming whitespace from tokens to prevent authentication failures
    • Improved whitespace normalization in authentication headers for better token processing
  • New Features

    • Added fallback support between authentication modes for improved resilience when the primary method becomes unavailable

Use intelligent probe fallback so Claude can recover from /usage parse failures by using OAuth API quotas, and harden long-lived token normalization to avoid malformed auth headers.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 26, 2026

📝 Walkthrough

Walkthrough

The PR implements a multi-probe fallback mechanism for the Claude provider, allowing graceful switching between CLI and API usage probes when either fails. Additionally, whitespace normalization is applied to credential tokens during loading and in API request headers.

Changes

Cohort / File(s) Summary
Probe Fallback Logic
Sources/Domain/Provider/Claude/ClaudeProvider.swift
Introduces primaryProbe() and fallbackProbe() methods to support mode-aware probe selection with explicit fallback behavior. Updates refresh() to attempt fallback probe on primary probe failure, with conditional snapshot/error updates based on fallback success.
Token Whitespace Normalization
Sources/Infrastructure/Claude/ClaudeAPIUsageProbe.swift, Sources/Infrastructure/Claude/ClaudeCredentialLoader.swift
Expands whitespace trimming to include newlines and carriage returns (using .whitespacesAndNewlines) for API authorization headers and environment/file-based credential tokens, preventing malformed tokens with surrounding whitespace.
Fallback Behavior Tests
Tests/AcceptanceTests/ClaudeConfigSpec.swift
Adds two acceptance tests validating fallback scenarios: API mode falling back to CLI when OAuth is unavailable, and CLI mode falling back to API when CLI parsing fails.
Token Normalization Tests
Tests/InfrastructureTests/Claude/ClaudeAPIUsageProbeTests.swift, Tests/InfrastructureTests/Claude/ClaudeCredentialLoaderTests.swift
Adds unit tests verifying newline trimming in authorization headers and whitespace normalization of environment-loaded tokens.

Sequence Diagram(s)

sequenceDiagram
    participant Caller
    participant Provider as ClaudeProvider
    participant Primary as primaryProbe()
    participant Fallback as fallbackProbe()
    participant Snapshot as snapshot

    Caller->>Provider: refresh()
    Provider->>Primary: probe() for usage snapshot
    
    alt Primary Succeeds
        Primary-->>Provider: snapshot returned
        Provider->>Snapshot: update with success
        Provider-->>Caller: success
    else Primary Fails
        Primary-->>Provider: error thrown
        Provider->>Fallback: attempt fallbackProbe()
        
        alt Fallback Available
            Fallback->>Fallback: probe() for usage snapshot
            
            alt Fallback Succeeds
                Fallback-->>Provider: snapshot returned
                Provider->>Snapshot: update with fallback snapshot
                Provider->>Provider: clear lastError
                Provider-->>Caller: success via fallback
            else Fallback Fails
                Fallback-->>Provider: error thrown
                Provider-->>Caller: propagate error
            end
        else No Fallback Available
            Provider-->>Caller: propagate primary error
        end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 A probe falls, but fear not, dear friend!
For fallback paths await at the bend.
From CLI to API, we softly switch—
Trimmed tokens shine, no whitespace glitch.
Graceful degradation, oh what a delight!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main changes: improving Claude setup-token OAuth usage and implementing API fallback behavior.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
Sources/Domain/Provider/Claude/ClaudeProvider.swift (1)

164-173: Preserve primary failure context when fallback probe also fails.

On Line 171/Line 172, lastError and thrown error become fallback-only, which hides the original failure cause from diagnostics.

♻️ Proposed fix
-        } catch {
+        } catch let primaryError {
             if let fallback = await fallbackProbe() {
                 do {
                     let newSnapshot = try await fallback.probe()
                     snapshot = newSnapshot
                     lastError = nil
                     return newSnapshot
-                } catch {
-                    lastError = error
-                    throw error
+                } catch let fallbackError {
+                    lastError = primaryError
+                    throw fallbackError
                 }
             }
 
-            lastError = error
-            throw error
+            lastError = primaryError
+            throw primaryError
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Sources/Domain/Provider/Claude/ClaudeProvider.swift` around lines 164 - 173,
The current logic overwrites the primary probe failure with the fallback error,
losing original context; modify the block in ClaudeProvider (around
fallbackProbe(), snapshot, lastError) to capture and keep the original error
before invoking fallback.probe(), and if the fallback also throws, set lastError
to a composite error that preserves both the primary and fallback errors (or
attach the primary as an underlying/inner error) and rethrow the fallback error
(or the composite) so diagnostic code can access both failures; ensure when
fallback succeeds you still clear lastError and update snapshot as before.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@Sources/Domain/Provider/Claude/ClaudeProvider.swift`:
- Around line 164-173: The current logic overwrites the primary probe failure
with the fallback error, losing original context; modify the block in
ClaudeProvider (around fallbackProbe(), snapshot, lastError) to capture and keep
the original error before invoking fallback.probe(), and if the fallback also
throws, set lastError to a composite error that preserves both the primary and
fallback errors (or attach the primary as an underlying/inner error) and rethrow
the fallback error (or the composite) so diagnostic code can access both
failures; ensure when fallback succeeds you still clear lastError and update
snapshot as before.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4f52480 and b295b1c.

📒 Files selected for processing (6)
  • Sources/Domain/Provider/Claude/ClaudeProvider.swift
  • Sources/Infrastructure/Claude/ClaudeAPIUsageProbe.swift
  • Sources/Infrastructure/Claude/ClaudeCredentialLoader.swift
  • Tests/AcceptanceTests/ClaudeConfigSpec.swift
  • Tests/InfrastructureTests/Claude/ClaudeAPIUsageProbeTests.swift
  • Tests/InfrastructureTests/Claude/ClaudeCredentialLoaderTests.swift

@codecov
Copy link

codecov bot commented Feb 26, 2026

Codecov Report

❌ Patch coverage is 86.95652% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 78.04%. Comparing base (481e57a) to head (b295b1c).
⚠️ Report is 92 commits behind head on main.

Files with missing lines Patch % Lines
...ources/Domain/Provider/Claude/ClaudeProvider.swift 91.42% 3 Missing ⚠️
...Infrastructure/Claude/ClaudeCredentialLoader.swift 70.00% 3 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #133      +/-   ##
==========================================
+ Coverage   77.97%   78.04%   +0.06%     
==========================================
  Files          78       79       +1     
  Lines        6048     6121      +73     
==========================================
+ Hits         4716     4777      +61     
- Misses       1332     1344      +12     
Files with missing lines Coverage Δ
...es/Infrastructure/Claude/ClaudeAPIUsageProbe.swift 90.47% <100.00%> (ø)
...ources/Domain/Provider/Claude/ClaudeProvider.swift 86.66% <91.42%> (-7.78%) ⬇️
...Infrastructure/Claude/ClaudeCredentialLoader.swift 57.96% <70.00%> (-0.21%) ⬇️

... and 4 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@hanrw hanrw merged commit 53667aa into tddworks:main Feb 26, 2026
5 checks passed
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