---
title: "Adding Google sign-in so non-developers can use your app"
date: 2026-09-14
tags: [oauth, google-sign-in, authentication, identity, web]
type: success
status: n/a
reproducible: true
stack: "Google OAuth 2.0 · Python/AWS Lambda backend · vanilla-JS SPA"
agent: "Claude Code"
---

# Adding Google sign-in so non-developers can use your app

My site had exactly one way in: GitHub. Perfect for developers and their agents
— but I started onboarding people who aren't developers, and asking a baker to
create a GitHub account just to save a favorite is absurd. They all have a Gmail.
So I added "Continue with Google."

The web plumbing was the easy half. Two things actually cost time.

Identity. My database keyed every user by their GitHub username. Google users
don't have one, and I didn't want ugly URLs like /a/10982374. So on first Google
sign-in the person picks a worklore handle, and I map their Google account id to
it permanently. The new record types had to be filtered out of every listing so
they never show as broken cards — and one of them, a cross-account favorites
merge in localStorage, bit me in testing: a new user inherited the previous
user's saved list.

The Google Console. The docs make it sound like "create an OAuth client." In
practice you also fill a Branding screen (logo, home page, and LIVE privacy +
terms URLs), add your authorized domain, and — the step nobody mentions — flip
the consent screen from Testing to Production, past a "send for verification"
button you can ignore as long as you only request the basic openid/email/profile
scopes. Miss any of these and real users get "access blocked."

An hour of work, and now anyone with a Gmail can sign in.

## Reproduce this
Prerequisites: an app with (or without) one OAuth provider, a backend that can
make server-side HTTPS calls, and LIVE privacy + terms pages on your domain.
Your agent will need from you: which provider, your domain, and how a user is
keyed today.
Steps:
1. Register the OAuth app — Google Cloud Console, in full:
   - Create a project: https://console.cloud.google.com/projectcreate
   - Branding / OAuth consent screen: app name, a square logo, Application home
     page, a LIVE privacy-policy URL and Terms URL, and your Authorized domain.
   - Scopes: request only openid, email, profile (non-sensitive → no
     verification review, no user cap, no "unverified app" screen).
   - Credentials → OAuth client ID → Web application: Authorized JS origin
     https://example.com and redirect URI https://example.com/auth/google/callback.
   - Publish: switch Testing → Production ("Publish app"). Do NOT "send for
     verification" for basic scopes — the button is there but not required.
2. Store the client secret in a secrets manager (e.g. AWS SSM SecureString),
   never in code; the client ID is public and can ship in the frontend.
3. Backend, server-side: POST code + client_id + client_secret + redirect_uri +
   grant_type=authorization_code to https://oauth2.googleapis.com/token, then GET
   https://www.googleapis.com/oauth2/v3/userinfo with the access_token to read
   sub, email, name, picture. No JWT library needed.
4. Identity: key the account by the provider's stable `sub`, not email. If your
   users have no natural handle, have them choose one on first sign-in and map
   provider-sub → handle. Exclude any new record types from every listing.
5. Frontend: one sign-in page with a button per provider + Terms/Privacy links;
   the button redirects with response_type=code, scope, and an anti-forgery
   state; the callback posts the code to your backend and stores the session.
Verify: sign in with a brand-new provider account in a private window — a new
user record is created and the session persists on reload. Then sign out and
sign in as a DIFFERENT account and confirm no data (favorites, drafts) carries
across. Open the consent screen as a non-test user to confirm it's really
published (no "access blocked").
