# Google sign-in What has to be true outside the repository for the Google button to work, and what to do at the domain cutover. The code side is #332 and the six issues under it; this is only the parts that live in a browser tab at Google. ## Where it is configured The **Google Auth Platform** in the Google Cloud Console, in one project. There is one consent screen per project and every OAuth client in it shares that screen, so what appears there is the production identity even while testing. | Section | What it holds | | --- | --- | | Branding | App name, support email, authorized domains, the three app links | | Audience | External, publishing status, test users | | Clients | The OAuth client, its redirect URIs, the id and secret | | Data Access | Exactly `openid`, `email`, `profile` | | Verification Center | Nothing to submit, and it should stay that way | ## The constraint that shapes everything **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. `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 | | --- | --- | | 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 | 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. `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. ## Scopes, and why publishing needs no review `openid` produces the id token carrying the subject claim, which is the identity stored. `email` carries the address and the `email_verified` flag the linking policy turns on. `profile` carries the names used when an account is created. All three are non-sensitive. Requesting only them is what lets the app publish without verification and without customers seeing an unverified-app warning. **Add one sensitive scope and publishing becomes a review with a video 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. ## 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: `https://qa.redefined-designs.com/api/auth/google/callback` 4. 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**. Do it once the domain resolves, so the home page and privacy links Google shows actually answer. 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. **Leaving it in Testing is the failure to watch for.** Only listed test users can sign in, and the refusal happens on Google's own page, so nothing reaches the storefront and nothing appears in its logs. A customer reports a broken button and the logs are silent. ## The production smoke test The consent screen, the redirect and the domain are all environment-specific, so QA proves the flow and not the configuration. After the cutover: 1. Sign in with a Google account that has never been used on the site. A new customer is created and lands on the consent step. 2. Sign in again with the same account. It reaches the same customer rather than a second one. 3. Check the account page lists Google under connected accounts. ## What is not offered, and why **Unlinking.** A customer cannot detach their Google account. Removing the only way into an account is guarded for passkeys and the same guard would be needed here first. Worth its own issue when somebody actually asks. **Apple.** A separate decision with a materially different cost, set out on #332: a paid developer programme, a client secret that expires every six months, no `localhost` redirect URIs at all, and a name and email returned exactly once. Apple is required for iOS apps offering third-party sign-in, and this is a website, so that rule does not apply here.