Skip to content

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:

  1. Accepts GET /{secret-slug}/{path} requests
  2. Validates the first path segment against a stored secret
  3. Injects CF Access service token headers
  4. Proxies the request to the protected origin
  5. 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.online app (requiring auth) before the ops.ucca.online/docs-proxy/ app (bypass), blocking unauthenticated requests
  • The Stripe Webhook Bypass at ops.ucca.online/api/stripe/webhook works because it was created with skip_interstitial: true via 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

surfaces/ucca-surfaces/workers/docs-proxy/
surfaces/ucca-surfaces/workers/knowledge-proxy/

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

  1. Copy either Worker directory:

    cp -r workers/docs-proxy workers/{new-name}-proxy
    

  2. Update wrangler.jsonc — change name to {new-name}-proxy

  3. Update src/index.ts — change the env interface secret name and the upstream URL

  4. Generate a new secret slug:

    python3 -c "import secrets; print('ucca-{slug}-' + secrets.token_hex(10)[:16])"
    

  5. Install and deploy:

    cd workers/{new-name}-proxy
    npm install
    npm run deploy
    

  6. Set secrets:

    echo -n "{generated-slug}" | wrangler secret put {NEW_NAME}_PROXY_SECRET
    echo -n "{client-id}" | wrangler secret put CF_ACCESS_CLIENT_ID
    echo -n "{client-secret}" | wrangler secret put CF_ACCESS_CLIENT_SECRET
    

  7. 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

  8. Verify:

    # Should return 200 with real HTML
    curl -s -o /dev/null -w "%{http_code}" "https://{new-name}-proxy.round-union-555d.workers.dev/{slug}/"
    
    # Should return 403
    curl -s -o /dev/null -w "%{http_code}" "https://{new-name}-proxy.round-union-555d.workers.dev/wrong/"
    

  9. 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_SECRET with a new value. Old URLs stop working immediately.
  • Revoke all proxy access: Delete the claude-docs-reader service 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