diff --git a/backend/src/google/config.ts b/backend/src/google/config.ts index 810985b..199ce00 100644 --- a/backend/src/google/config.ts +++ b/backend/src/google/config.ts @@ -14,27 +14,32 @@ * source, and it is the one that is already correct in any environment where * mail works. * - * ## The consequence worth stating plainly + * ## Every environment needs its own console entry * - * Google refuses a redirect URI whose host is not under an **authorized - * domain**, and a domain can only be authorized after ownership has been proved - * by DNS in Search Console. `localhost` is the sole exemption. + * Whatever this resolves to has to exist, verbatim, under Authorized redirect + * URIs for the client this app uses. Google compares the two as strings, and a + * mismatch is answered with `redirect_uri_mismatch` — accurate, and silent + * about which half is wrong. * - * `qa-redefined-designs.bermudalamb.synology.me` therefore **cannot ever be - * used**: Synology owns the registrable domain above it, so there is no record - * to add and nothing to prove. This is the same wall #285 hit with Cloudflare. + * | Environment | Redirect URI | + * | --- | --- | + * | Local, Vite | `http://localhost:5173/api/auth/google/callback` | + * | Local, built | `http://localhost:3000/api/auth/google/callback` | + * | QA | `https://qa-redefined-designs.bermudalamb.synology.me/api/auth/google/callback` | + * | Production | `https://redefined-designs.com/api/auth/google/callback` | * - * | Environment | Redirect URI | Works | - * | --- | --- | --- | - * | Local | `http://localhost:3000/...` | Yes, by exemption | - * | QA on the Synology host | — | **No, and cannot** | - * | QA on `qa.redefined-designs.com` | `https://qa.redefined-designs.com/...` | After #313 | - * | Production | `https://redefined-designs.com/...` | After #313 | + * Local development needs the 5173 one, because that is where the dev server + * serves the app; the 3000 one only applies when the backend serves a built + * frontend. * - * So this feature is built and exercised locally, and QA cannot see it until QA - * moves onto a subdomain of the real domain. That is a `PUBLIC_URL` change and - * one console entry, not a code change — this module follows `PUBLIC_URL` - * wherever it points. See #345. + * An earlier version of this comment claimed the QA hostname could never be + * registered, because it sits under a domain Synology owns. **That was wrong**, + * and it is recorded here rather than quietly deleted: it was asserted from the + * shape of #285, which is a related but different problem, and it sent QA + * testing of this feature behind #313 for no reason. Adding the URI works. + * + * This module needs no change in any environment. It follows `PUBLIC_URL` + * wherever it points. */ /** The callback path. One constant, because it appears in two sentences. */ diff --git a/docker-compose.qa.yml b/docker-compose.qa.yml index b553726..eb48014 100644 --- a/docker-compose.qa.yml +++ b/docker-compose.qa.yml @@ -65,12 +65,10 @@ # production's: a link signed with it acts without a login. # QA_GOOGLE_CLIENT_ID — optional, and all-or-nothing with the secret below: # QA_GOOGLE_CLIENT_SECRET setting one without the other refuses to boot -# (#340). Both unset means the Google button is simply not -# offered, which is the right answer while QA lives on a -# *.synology.me hostname — Google will not accept a redirect -# URI whose domain nobody can prove they own, so a button -# there could only ever fail. Set them once QA moves to -# qa.redefined-designs.com (#313, #345). +# (#340). Both unset means the Google button is not offered +# at all, which is the right answer until QA's callback URL +# is registered in the Google Auth Platform. See the note +# beside the values themselves for the exact URL (#345). # QA_REMBG_URL — optional. The background-removal sidecar, e.g. # http://rembg-syn:7000. Unset turns the feature off rather # than breaking anything. The sidecar must be on the same @@ -208,16 +206,21 @@ services: # odd one out and cost a QA deploy: the variables were set on the stack, # nothing read them, and the button stayed missing with no explanation. # - # Leave them UNSET until QA moves off *.bermudalamb.synology.me. Google - # refuses a redirect URI whose host is not under a domain whose ownership - # has been proved by DNS, and nobody can prove ownership of that one, - # because Synology owns the registrable domain above it — the same wall - # #285 hit. Setting them today produces a button that fails at Google with - # redirect_uri_mismatch, and no console entry can satisfy it. + # Setting these needs one thing done first: the QA callback registered + # under Authorized redirect URIs for this client in the Google Auth + # Platform, exactly as it appears below. Google compares the two as + # strings and answers a mismatch with redirect_uri_mismatch. # - # Once #313 moves QA to qa.redefined-designs.com: set these two, point - # PUBLIC_URL at the new host, and add the matching callback under Clients - # in the Google Auth Platform. No code change either way (#345). + # https://qa-redefined-designs.bermudalamb.synology.me/api/auth/google/callback + # + # An earlier version of this comment said that URI could never be + # registered, because Synology owns the domain above it. That was wrong, + # and the correction is left here rather than removed: it was inferred + # from #285, which is a related but different problem, and it put QA + # testing of this feature behind #313 for no reason. + # + # When #313 moves QA to qa.redefined-designs.com, point PUBLIC_URL at the + # new host and register that callback too. No code change either way. - GOOGLE_CLIENT_ID=${QA_GOOGLE_CLIENT_ID:-} - GOOGLE_CLIENT_SECRET=${QA_GOOGLE_CLIENT_SECRET:-} volumes: diff --git a/docs/ops/google-sign-in.md b/docs/ops/google-sign-in.md index ad603f8..7e79650 100644 --- a/docs/ops/google-sign-in.md +++ b/docs/ops/google-sign-in.md @@ -18,33 +18,42 @@ screen, so what appears there is the production identity even while testing. | Data Access | Exactly `openid`, `email`, `profile` | | Verification Center | Nothing to submit, and it should stay that way | -## The constraint that shapes everything +## Redirect URIs, one per environment -**Google refuses a redirect URI whose host is not under an authorized domain, -and a domain can only be authorized after ownership is proved by DNS in Search -Console.** `localhost` is the only exemption. +Every environment sends a redirect URI derived from its own `PUBLIC_URL`, and +each one has to exist verbatim under **Authorized redirect URIs** on the client +this app uses. Google compares them as strings and answers a mismatch with +`redirect_uri_mismatch`, which is accurate and says nothing about which half is +wrong. -`qa-redefined-designs.bermudalamb.synology.me` therefore cannot ever be used: -Synology owns the registrable domain above it, so there is no record to add and -nothing to prove. This is the same wall #285 hit with Cloudflare. - -The consequence, stated plainly because it changes how the feature is worked on: - -| Environment | Google sign-in | +| Environment | Redirect URI | | --- | --- | -| Local, on `localhost` | Works, by exemption | -| QA on the Synology hostname | **Impossible**, not merely unconfigured | -| QA on `qa.redefined-designs.com` | Works, after the cutover | -| Production on `redefined-designs.com` | Works, after the cutover | +| Local, Vite dev server | `http://localhost:5173/api/auth/google/callback` | +| Local, backend serving a build | `http://localhost:3000/api/auth/google/callback` | +| QA | `https://qa-redefined-designs.bermudalamb.synology.me/api/auth/google/callback` | +| Production | `https://redefined-designs.com/api/auth/google/callback` | -So this feature is built and exercised locally, and QA cannot see it at all -until QA moves onto a subdomain of the real domain. The Search Console property -for `redefined-designs.com` already covers `qa.redefined-designs.com`, because -a Domain property covers every subdomain. +Local development needs the 5173 entry, because that is where the dev server +serves the app. The 3000 one applies only when the backend serves a built +frontend, which local development does not produce. -`docker-compose.qa.yml` sets both credentials to empty deliberately, with a -comment saying so, and the storefront then offers no button rather than one that -fails at Google. +### A correction + +An earlier version of this document said the QA hostname **could never be +registered**, because it sits under a domain Synology owns rather than one we +do. That was wrong. Adding the URI works. + +The claim is recorded here rather than quietly removed, because of what it +cost. It was inferred from #285, where Cloudflare genuinely cannot be applied to +that hostname, and asserted with far more confidence than the inference +supported. On the strength of it, QA testing of Google sign-in was documented as +blocked behind #313, the QA compose file hardcoded its credentials to empty, and +two issues recorded it as fact. + +What is true, and is all that was ever established: `localhost` is exempt from +the authorized-domain rules, and a domain listed as an authorized domain has to +be verified in Search Console. Whether either of those actually applied to this +hostname, and how, was never checked. ## Scopes, and why publishing needs no review @@ -60,20 +69,35 @@ walkthrough and a wait measured in weeks.** Nothing in this feature needs one. Uploading an app logo also triggers a brand review, which is why Branding has none. +## Turning it on in QA + +Already done, and recorded here because the order matters. + +1. Register the QA callback under **Clients**, Authorized redirect URIs: + `https://qa-redefined-designs.bermudalamb.synology.me/api/auth/google/callback` +2. Set `QA_GOOGLE_CLIENT_ID` and `QA_GOOGLE_CLIENT_SECRET` on the QA stack. Both + or neither — the backend refuses to start on one without the other, because + the failure would otherwise arrive the moment a customer presses the button. +3. Redeploy. + +Registering first is the point. Setting the variables makes the button appear, +and a button that appears before its callback exists fails at Google rather than +in the storefront, where nothing in the logs explains it. + ## The cutover checklist, for #313 1. Point QA at `qa.redefined-designs.com` and set its `PUBLIC_URL` to match. -2. Set `GOOGLE_CLIENT_ID` and `GOOGLE_CLIENT_SECRET` in the QA stack. Both or - neither — the backend refuses to start on one without the other, because the - failure would otherwise arrive the moment a customer presses the button. -3. In **Clients**, add the QA callback: +2. In **Clients**, add the new QA callback: `https://qa.redefined-designs.com/api/auth/google/callback` -4. Confirm the production callback is registered: +3. Confirm the production callback is registered: `https://redefined-designs.com/api/auth/google/callback` -5. In **Audience**, move the publishing status from Testing to **In production**. +4. In **Audience**, move the publishing status from Testing to **In production**. Do it once the domain resolves, so the home page and privacy links Google shows actually answer. +The old QA callback can be left registered until the hostname is retired. An +extra entry costs nothing and removing it early breaks QA for no gain. + No code changes at any step. The redirect URI is derived from `PUBLIC_URL`, so the environment variable and the console entry are the whole of it.