fix: include anthropic.com cookies in all auth checks and API requests

Claude session cookies are on anthropic.com, not claude.ai. The login
window was not detecting auth (Cancel stayed, no Done) and API calls
were sent without the actual session token.

- claudeCookieHeader: include anthropic.com cookies so the token is
  sent to the usage/bootstrap endpoints
- checkInitialSignInState: detect anthropic.com cookies on startup
- didFinish in LoginView: fire auth when anthropic.com cookies found
- signOut: clear anthropic.com data alongside claude.ai
- notAuthenticated catch: set isSignedIn = false so Settings stays
  in sync with the main panel
This commit is contained in:
superdooper86
2026-05-11 09:49:57 +02:00
parent 2e3ee350ca
commit aaed64484c
4 changed files with 10 additions and 7 deletions
+2 -2
View File
@@ -15,9 +15,9 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>1.2.1-beta.6</string> <string>1.2.1-beta.7</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>54</string> <string>55</string>
<key>LSMinimumSystemVersion</key> <key>LSMinimumSystemVersion</key>
<string>13.0</string> <string>13.0</string>
<key>LSUIElement</key> <key>LSUIElement</key>
+1 -1
View File
@@ -38,7 +38,7 @@ struct LoginWebView: NSViewRepresentable {
// URL is not a login/auth page, so if any claude.ai cookie exists we're signed in // URL is not a login/auth page, so if any claude.ai cookie exists we're signed in
WKWebsiteDataStore.default().httpCookieStore.getAllCookies { cookies in WKWebsiteDataStore.default().httpCookieStore.getAllCookies { cookies in
let hasAnyCookie = cookies.contains { $0.domain.contains("claude.ai") } let hasAnyCookie = cookies.contains { $0.domain.contains("claude.ai") || $0.domain.contains("anthropic.com") }
guard hasAnyCookie, !self.didAuthenticate else { return } guard hasAnyCookie, !self.didAuthenticate else { return }
self.didAuthenticate = true self.didAuthenticate = true
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
+4 -3
View File
@@ -43,7 +43,7 @@ class UsageViewModel: ObservableObject {
private func checkInitialSignInState() async { private func checkInitialSignInState() async {
let cookies = await WKWebsiteDataStore.default().httpCookieStore.allCookies() let cookies = await WKWebsiteDataStore.default().httpCookieStore.allCookies()
let hasAnyCookie = cookies.contains { $0.domain.contains("claude.ai") } let hasAnyCookie = cookies.contains { $0.domain.contains("claude.ai") || $0.domain.contains("anthropic.com") }
if hasAnyCookie { isSignedIn = true } if hasAnyCookie { isSignedIn = true }
} }
@@ -51,7 +51,7 @@ class UsageViewModel: ObservableObject {
let store = WKWebsiteDataStore.default() let store = WKWebsiteDataStore.default()
let types = WKWebsiteDataStore.allWebsiteDataTypes() let types = WKWebsiteDataStore.allWebsiteDataTypes()
let records = await store.dataRecords(ofTypes: types) let records = await store.dataRecords(ofTypes: types)
let claudeRecords = records.filter { $0.displayName.contains("claude.ai") } let claudeRecords = records.filter { $0.displayName.contains("claude.ai") || $0.displayName.contains("anthropic.com") }
await store.removeData(ofTypes: types, for: claudeRecords) await store.removeData(ofTypes: types, for: claudeRecords)
UserDefaults.standard.removeObject(forKey: "claude_org_id") UserDefaults.standard.removeObject(forKey: "claude_org_id")
isSignedIn = false isSignedIn = false
@@ -109,6 +109,7 @@ class UsageViewModel: ObservableObject {
checkLimitNotifications(for: limits) checkLimitNotifications(for: limits)
} catch AppError.notAuthenticated { } catch AppError.notAuthenticated {
isNotAuthenticated = true isNotAuthenticated = true
isSignedIn = false
errorMessage = "Not signed in" errorMessage = "Not signed in"
} catch let error as DecodingError { } catch let error as DecodingError {
switch error { switch error {
@@ -192,7 +193,7 @@ class UsageViewModel: ObservableObject {
private func claudeCookieHeader() async -> String? { private func claudeCookieHeader() async -> String? {
let cookies = await WKWebsiteDataStore.default().httpCookieStore.allCookies() let cookies = await WKWebsiteDataStore.default().httpCookieStore.allCookies()
let claudeCookies = cookies.filter { $0.domain.contains("claude.ai") } let claudeCookies = cookies.filter { $0.domain.contains("claude.ai") || $0.domain.contains("anthropic.com") }
return HTTPCookie.requestHeaderFields(with: claudeCookies)["Cookie"] return HTTPCookie.requestHeaderFields(with: claudeCookies)["Cookie"]
} }
+3 -1
View File
@@ -6,4 +6,6 @@
- Fixed login window auto-closing before the user could sign in — the login window now correctly loads the `/login` page so it only detects auth after the actual sign-in redirect - Fixed login window auto-closing before the user could sign in — the login window now correctly loads the `/login` page so it only detects auth after the actual sign-in redirect
- Fixed "No API key configured" showing after signing out — now correctly shows "Not signed in" with a prompt to sign in - Fixed "No API key configured" showing after signing out — now correctly shows "Not signed in" with a prompt to sign in
- Added `/api/organizations` as a final fallback for org ID resolution when the bootstrap API response doesn't include it - Added `/api/organizations` as a final fallback for org ID resolution when the bootstrap API response doesn't include it
- Fixed usage data not loading after sign-in — API requests now include required browser-like headers (Origin, Referer, User-Agent) that Claude's usage endpoints require - Fixed usage data not loading — API requests now include required browser-like headers (Origin, Referer, User-Agent)
- Fixed sign-in detection and cookie handling for accounts whose session cookies are on the `anthropic.com` domain rather than `claude.ai`
- Fixed Settings incorrectly showing "Signed in" after a failed refresh — sign-in state now resets when authentication fails