Runbook — Claude Proxy Access¶
Problem¶
Claude's web_fetch tool cannot send custom HTTP headers. Sites protected by Cloudflare Access (docs.ucca.online, knowledge.ucca.online) require CF-Access-Client-Id and CF-Access-Client-Secret headers to bypass SSO. Without these headers, Claude gets a 403 or a redirect to the CF Access login page.
Solution¶
Standalone Cloudflare Workers deployed on *.workers.dev subdomains. Each Worker:
- Accepts
GET /{secret-slug}/{path}requests - Validates the first path segment against a stored secret
- Injects CF Access service token headers
- Proxies the request to the protected origin
- Returns the response with CF Access headers stripped
The *.workers.dev domain has no CF Access application protecting it, so requests reach the Worker without interference.
Why Not a Path-Scoped CF Access Bypass¶
We tried adding a path-scoped CF Access application (e.g. ops.ucca.online/docs-proxy/) with a Bypass policy. This failed because:
skip_interstitial— the flag that makes Bypass policies work for machine clients — is only settable via the CF API, not the dashboard- Path-scoped apps don't reliably take priority over broader hostname apps. CF Access evaluated the
ops.ucca.onlineapp (requiring auth) before theops.ucca.online/docs-proxy/app (bypass), blocking unauthenticated requests - The Stripe Webhook Bypass at
ops.ucca.online/api/stripe/webhookworks because it was created withskip_interstitial: truevia API — replicating this via dashboard is not possible
A standalone Worker on a separate hostname eliminates CF Access entirely from the request path.
Security Model¶
The proxy is not a security bypass — it is a controlled relay:
- Secret slug in URL — only callers who know the slug can use the proxy. The slug is a ~24-character random string stored as a Worker secret
- GET only — POST, PUT, DELETE, PATCH all return 405
- Origin CF Access wall remains intact — the Worker authenticates to the origin using a non-expiring CF Access service token. The origin still validates the token. Revoking the service token kills all proxy access instantly
- No cookies, no sessions — the proxy is stateless. Each request is independently authenticated against the origin
- Cache-Control: no-store — responses are never cached
Current Proxies¶
| Protected Site | Worker | Proxy Base URL |
|---|---|---|
| docs.ucca.online | docs-proxy |
https://docs-proxy.round-union-555d.workers.dev/ucca-docs-w9zweudo02aocz74/ |
| knowledge.ucca.online | knowledge-proxy |
https://knowledge-proxy.round-union-555d.workers.dev/ucca-know-732499f9d740c605/ |
Worker Locations¶
CF Access Service Token¶
- Token name:
claude-docs-reader - Duration: Non-expiring
- Policy: "Service Token Bypass" (SERVICE AUTH) — attached to both "UCCA Docs" and "UCCA Knowledge" CF Access applications
Adding a New Proxy¶
-
Copy either Worker directory:
-
Update
wrangler.jsonc— changenameto{new-name}-proxy -
Update
src/index.ts— change the env interface secret name and the upstream URL -
Generate a new secret slug:
-
Install and deploy:
-
Set secrets:
-
Ensure the CF Access application for the target site has the "Service Token Bypass" (SERVICE AUTH) policy attached. If it's a new site, add the policy via Zero Trust → Access → Applications → {app} → Edit → Policies → Select existing policies
-
Verify:
-
Give Claude the proxy URL directly in chat — Claude needs the URL once per session to whitelist it for
web_fetch
Revoking Access¶
- Rotate a single proxy's slug:
wrangler secret put {NAME}_PROXY_SECRETwith a new value. Old URLs stop working immediately. - Revoke all proxy access: Delete the
claude-docs-readerservice token in CF Zero Trust → Access → Service Auth. All proxies lose upstream access. - Delete a proxy:
wrangler delete --name {worker-name}
Version History¶
| Version | Date | Change | Author |
|---|---|---|---|
| 1.0 | 2026-03-11 | Initial creation | Claude Code |