Skip to content

Conversation

@willsheldon
Copy link

Summary

  • Replace URLSession-based NetworkService with WKWebView-based implementation to bypass Cloudflare's bot protection on Claude.ai API endpoints
  • Fix organization selection to prefer orgs with "chat" capability for users with multiple organizations
  • Add capabilities field to Organization model

Problem

Cloudflare recently started blocking requests from URLSession due to TLS fingerprint mismatch. The cf_clearance cookie is tied to browser TLS fingerprints, so simple HTTP clients (URLSession, curl) cannot pass JavaScript challenges even with valid session keys.

Solution

Created WebViewNetworkService using WKWebView which shares Safari's TLS stack. WKWebView automatically handles Cloudflare JS challenges and has the correct TLS fingerprint that Cloudflare expects.

The service polls page content until valid JSON is detected, handling the delay while Cloudflare challenges complete.

Additional Fixes

  • Added capabilities field to Organization model with hasChatCapability helper
  • Updated org selection in UsageService and AppModel to prefer organizations with "chat" capability
  • This fixes issues for users with multiple orgs (API-only vs Claude.ai personal org)
  • Added timeout case to NetworkError enum
  • Changed NetworkServiceProtocol from Actor to Sendable constraint to support @mainactor classes

Test plan

  • Build succeeds
  • App launches and displays usage data in menu bar
  • Verified API requests bypass Cloudflare (no 403 errors)
  • Verified correct organization is selected for users with multiple orgs

🤖 Generated with Claude Code

Replace URLSession-based NetworkService with WKWebView-based implementation
to bypass Cloudflare's bot protection on Claude.ai API endpoints.

Problem:
- Cloudflare blocks requests from URLSession due to TLS fingerprint mismatch
- The cf_clearance cookie is tied to browser TLS fingerprints
- Simple HTTP clients (URLSession, curl) cannot pass JS challenges

Solution:
- Created WebViewNetworkService using WKWebView which shares Safari's TLS stack
- WKWebView automatically handles Cloudflare JS challenges
- Polls page content until valid JSON is detected (handles challenge delays)

Additional fixes:
- Added 'capabilities' field to Organization model
- Updated org selection to prefer orgs with 'chat' capability
- This fixes issues for users with multiple orgs (API-only vs Claude.ai)
- Added 'timeout' case to NetworkError enum
- Changed NetworkServiceProtocol from Actor to Sendable constraint

Files changed:
- New: WebViewNetworkService.swift - WKWebView-based network service
- Modified: AppModel.swift - Use WebViewNetworkService, fix org selection
- Modified: UsageService.swift - Prefer chat-capable organizations
- Modified: Organization.swift - Add capabilities field and helper
- Modified: NetworkServiceProtocol.swift - Sendable instead of Actor
- Modified: NetworkError.swift - Add timeout case

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
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