Conversation
Reads from Claude Code's Keychain item trigger a macOS authorization dialog on every poll. Cache the extracted token in a ClaudeCodeStats- owned Keychain item and in memory. Invalidate both on 401/403. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR reduces repeated macOS Keychain authorization prompts by caching Claude Code’s OAuth access token in an app-owned Keychain item and also caching it in-memory for the current session, with cache invalidation on 401/403 responses.
Changes:
- Add an in-memory access token cache to avoid repeated file/Keychain reads during a session.
- Add an app-owned Keychain item (
ClaudeCodeStats-credentials) to persist the token and avoid repeatedly reading Claude Code’s Keychain item. - Clear both the in-memory and app Keychain caches when the API returns 401/403.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
ClaudeCodeStats/ClaudeCodeStats/Services/OAuthUsageService.swift
Outdated
Show resolved
Hide resolved
- Add @mainactor to OAuthUsageService for thread safety on cachedToken - Log failures on SecItemAdd and SecItemDelete instead of ignoring status - Remove side effects from hasCredentials (no longer mutates cache or writes to Keychain) - Add comment clarifying why readTokenFromAppKeychain is separate from readTokenFromKeychain Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 1 out of 1 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
ClaudeCodeStats/ClaudeCodeStats/Services/OAuthUsageService.swift
Outdated
Show resolved
Hide resolved
…nique Keychain addressing
- hasCredentials now delegates to readAccessToken() so the in-memory
cache is populated on first check, avoiding repeated file/Keychain I/O
- Add fixed kSecAttrAccount ("oauth-token") to all app-Keychain queries
so the cached token item is uniquely addressed
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 1 out of 1 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (1)
ClaudeCodeStats/ClaudeCodeStats/Services/OAuthUsageService.swift:22
@MainActoron the whole service forces all synchronous file/keychain I/O inreadAccessToken()(and anyhasCredentialsevaluation) to run on the main actor.FileManager.default.contents(atPath:)andSecItemCopyMatchingcan block, which may cause UI hitching during SwiftUI body evaluation or refresh. Consider removing the class-level@MainActor(or narrowing actor isolation) and performing the keychain/file reads off the main thread while keeping only UI-facing state updates on the main actor.
@MainActor
class OAuthUsageService {
static let shared = OAuthUsageService()
private let apiURL = "https://api.anthropic.com/v1/messages"
private let credentialsPath: String = {
let home = FileManager.default.homeDirectoryForCurrentUser.path
return "\(home)/.claude/.credentials.json"
}()
private let keychainService = "Claude Code-credentials"
private let appKeychainService = "ClaudeCodeStats-credentials"
private let appKeychainAccount = "oauth-token"
private var cachedToken: String?
private init() {}
var hasCredentials: Bool {
readAccessToken() != nil
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
ClaudeCodeStats/ClaudeCodeStats/Services/OAuthUsageService.swift
Outdated
Show resolved
Hide resolved
ClaudeCodeStats/ClaudeCodeStats/Services/OAuthUsageService.swift
Outdated
Show resolved
Hide resolved
- Rename reflects that both in-memory and Keychain caches are cleared - Set kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly to prevent iCloud Keychain sync and restrict access appropriately Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Summary
ClaudeCodeStats-credentialsKeychain item owned by the app, avoiding repeated macOS authorization prompts from reading Claude Code's Keychain itemTest plan
🤖 Generated with Claude Code