extremely claude-assisted go game based on atproto! working on cleaning up and giving a more unique design, still has a bit of a slop vibe t
cloud-go LOCAL_DEVELOPMENT.md
3.5 kB · 73 lines
Markdown

Local Development with OAuth #

Logging in locally works on a loopback origin — no tunnel, no signing key, no published metadata. That is the atproto spec's localhost exception: when the client_id is http://localhost?..., the authorization server synthesises the client metadata from the client_id's own query parameters instead of fetching a metadata document.

Two things to get right:

1. Open the app on 127.0.0.1, not localhost. The spec allows the client_id to be http://localhost but requires redirect URIs to be on 127.0.0.1 or [::1], so the app builds its redirect as http://127.0.0.1:<port>/auth/callback. Browse the same origin, otherwise the session cookie is set on a host you are not on.

2. Point each dev server's own env file at that origin. Both are gitignored, so a stale value is easy to miss; in particular, if either still points at the deployed URL, clicking Login hands you to production and the session lands on the wrong origin.

Dev server Reads Start PUBLIC_BASE_URL
wrangler pages dev (port 8788) .dev.vars npx wrangler pages dev --port 8788 http://127.0.0.1:8788
npm run dev (Vite, port 5173) .env npm run dev http://127.0.0.1:5173

wrangler pages dev serves the built worker, so run npm run build first (or npm run watch); it also provides the D1 and KV bindings that the Vite dev server does not have.

Loopback client vs. deployed client #

Loopback Deployed
Client type public (token_endpoint_auth_method: none) confidential (private_key_jwt)
client_id http://localhost?scope=...&redirect_uri=..., built by the library at startup <PUBLIC_BASE_URL>/oauth/v2/client-metadata.json
Metadata synthesised by the authorization server published by this app, fetched by the authorization server
PRIVATE_KEY_JWK unused required

getOAuthClient picks between the two from PUBLIC_BASE_URL alone.

Testing the deployed client configuration locally #

The deployed client publishes its metadata and signs its requests, so the authorization server has to be able to reach it over HTTPS. To exercise that path locally, tunnel the dev server and use the tunnel origin in the env file (this is the only reason a tunnel is needed):

npx wrangler pages dev --port 8788
npx ngrok http 8788                     # https://abc123.ngrok-free.app
# .dev.vars: PUBLIC_BASE_URL=https://abc123.ngrok-free.app

The free ngrok URL changes on every restart, so update the env file and restart the dev server each time. PRIVATE_KEY_JWK must be set (npm run setup:key).

Troubleshooting #

  • You end up on the production site when clicking Login. PUBLIC_BASE_URL in the env file the running dev server reads still points at production.
  • Missing sec-fetch-site header from bsky.social. You opened the authorizationUrl outside a browser (curl, a script). The authorization endpoint requires normal browser navigation; the login endpoint returns the URL for the page to navigate to rather than redirecting.
  • Logged out immediately after logging in. The callback landed on a different origin than the one you are browsing (localhost vs 127.0.0.1).

Production #

PUBLIC_BASE_URL is the deployed origin (https://go.sky.boo), set in wrangler.toml. PRIVATE_KEY_JWK, SESSION_SECRET and the KV bindings are Cloudflare secrets/bindings — see CLOUDFLARE_DEPLOYMENT.md.