feat(relay): capture signup country at sign-in via cf.country - #563
Open
felipesalinasr wants to merge 1 commit into
Open
feat(relay): capture signup country at sign-in via cf.country#563felipesalinasr wants to merge 1 commit into
felipesalinasr wants to merge 1 commit into
Conversation
We can't report users by country: Google OAuth returns no location, and the handle_new_user trigger that creates the profile row runs inside Postgres and never sees the request IP. Capture it server-side instead. - supabase: additive migration adds nullable profiles.signup_country (ISO alpha-2) + country_source. No backfill — no historical IPs exist. - houston-relay: new POST /capture-country reads request.cf.country (server-side, tamper-proof), verifies the caller's Supabase access token, and PATCHes their profile with the service role. Idempotent (only when signup_country is null); no IP is read or stored. - app: after sign-in, fire a non-blocking call to the relay route from auth.ts (both PKCE and implicit branches). Best-effort: failures only log and never affect sign-in. - tests: unit-test normalizeCountry (XX/T1/empty/malformed -> null). Deploy prerequisites (not in this diff): set SUPABASE_SERVICE_ROLE_KEY as a relay Worker secret (prod + --env staging) before deploying. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
We can't report users by country today. Google OAuth returns no location, and the
handle_new_userPostgres trigger that creates theprofilesrow runs inside Postgres and never sees the request IP — so country can't be captured there. This adds tamper-proof, server-side country capture with zero user-facing friction.How it works
profilesgets nullablesignup_country(ISO 3166-1 alpha-2) andcountry_source. Additive and backward-compatible.POST /capture-country(houston-relay) readsrequest.cf.country(Cloudflare-resolved, server-side, can't be spoofed by the client), verifies the caller's Supabase access token via GoTrue, and PATCHes their profile with the service role. Idempotent — only writes whensignup_countryis null, so re-logins never overwrite the first value.exchangeCodeForSession/setSessionsucceeds inapp/src/lib/auth.ts, a non-blocking, fire-and-forget call hits the relay route. Failures only log; they never block or fail sign-in.No IP is ever read or stored —
request.cf.countryis pre-resolved by Cloudflare. Country only, so this stays clear of GDPR PII handling.Files
supabase/migrations/20260621000000_profiles_country.sql— new columnshouston-relay/src/capture-country.ts— new route handler +normalizeCountryhouston-relay/src/index.ts— route wiringhouston-relay/src/types.ts—SUPABASE_URLvar +SUPABASE_SERVICE_ROLE_KEYsecrethouston-relay/wrangler.toml—SUPABASE_URL(prod + staging)houston-relay/test/capture-country.test.ts—normalizeCountryunit testsapp/src/lib/auth.ts— non-blocking capture call (both auth branches)Verification
pnpm --filter houston-relay typecheck— passesnormalizeCountrylogic verified (XX / T1 / empty / malformed → null; valid → upper-cased)SUPABASE_SERVICE_ROLE_KEYas a relay Worker secret:cd houston-relay && wrangler secret put SUPABASE_SERVICE_ROLE_KEY(and again with--env staging). The route no-ops (503) until it's set.houston-prod.SUPABASE_URLis correct if staging uses a separate Supabase project (currently points at the prod project).current_countryon each login.Notes
auth.audit_log_entriesis purged, so no historical IPs exist. Country is captured from launch forward only.🤖 Generated with Claude Code