This is the one-time, user-operated setup that lets "Sign in with Google" work end-to-end (Decision #12: the AI never creates cloud resources). You do not need this to build or run the test suite — tests use a self-signed key and mocked Google endpoints. You need it only for a live browser demo.
Result you're after: a Client ID and Client secret for a new OAuth client, pasted into the right secrets files.
One Google OAuth 2.0 Client ID (type Web application) under a Google
Cloud project. The App uses the client id + secret to run the login redirect;
the API uses only the client id to check the token's aud.
Per Decision #3, make a new client for Tyto Demo — do not reuse full Tyto's.
The consent-screen UI now lives under "Google Auth Platform" (the old "OAuth consent screen" menu). Concepts are unchanged.
-
Project — at https://console.cloud.google.com, create a project (e.g.
tyto-demo) or reuse one. Note which project you're in (top bar). -
Consent screen → Audience — APIs & Services → Google Auth Platform:
- User type: External (locked decision — supports any Google account, not just an org). Personal gmail is fine.
- App name + your support email; save.
- Audience page → add Test users: your gmail + each student's gmail (up to ~100). In Testing mode only listed users can sign in — perfect for a class, no review needed.
-
Scopes — request only
openid,email,profile. These are non-sensitive, so there's no verification review and no "unverified app" warning, even if you later publish. -
Clients → Create client:
-
Application type: Web application.
-
Name: e.g.
tyto-app. -
Authorized redirect URIs — add exactly (byte-for-byte; this is the #1 gotcha — Google matches scheme/host/port/path exactly, no trailing slash drift):
http://localhost:9292/auth/sso_callbackhttp://localhostis allowed over plain HTTP (Google exempts localhost from its HTTPS rule), so no TLS in dev. Add your deployed HTTPS URL later when you ship. Register each extra dev port separately. -
You can leave "Authorized JavaScript origins" empty — we use the server-side authorization-code flow, not the browser SDK.
-
Create → copy the Client ID and Client secret (shown now).
-
Both repos have a gitignored config/secrets.yml (copy from
secrets-example.yml if missing). Fill the development (and test) blocks.
| Value | API (tyto2026-api) |
App (tyto2026-app) |
|---|---|---|
GOOGLE_CLIENT_ID |
✅ needed (checks token aud) |
✅ needed (starts the redirect) |
GOOGLE_CLIENT_SECRET |
❌ never | ✅ needed (token exchange) |
GOOGLE_REDIRECT_URI |
❌ | ✅ http://localhost:9292/auth/sso_callback |
The API never sees the secret — it only verifies Google's signed id_token
against Google's public keys. The secret stays server-side in the App.
For the test environment in the API,
GOOGLE_CLIENT_IDcan be any placeholder string (the suite mints its own tokens with a matchingaud). It's already set insecrets-example.yml— no action needed for tests.
Optional (API only): the issuer and JWKS URL are hard-coded constants in the verifier, so you normally don't set them. If you ever need to override them (e.g. testing against a different OIDC provider), add
GOOGLE_ISSUER: 'https://accounts.google.com'andGOOGLE_JWKS_URL: 'https://www.googleapis.com/oauth2/v3/certs'to the API'sdevelopmentblock.
Per Decision #12 you run these (the AI does not touch cloud resources). Same client id as dev; the App also needs the secret + the prod redirect URI. Heroku example:
# API — id only (for the aud check)
heroku config:set -a <api-app-name> \
GOOGLE_CLIENT_ID='<id>.apps.googleusercontent.com'
# App — id + secret + prod redirect + endpoints/scope
heroku config:set -a <app-app-name> \
GOOGLE_CLIENT_ID='<id>.apps.googleusercontent.com' \
GOOGLE_CLIENT_SECRET='<secret>' \
GOOGLE_OAUTH_URL='https://accounts.google.com/o/oauth2/v2/auth' \
GOOGLE_TOKEN_URL='https://oauth2.googleapis.com/token' \
GOOGLE_SCOPE='openid email profile' \
GOOGLE_REDIRECT_URI='https://<your-app-host>/auth/sso_callback'Then add that prod redirect URI to the Console client (Step 4) — it must be registered there too (byte-for-byte, HTTPS off-localhost) or Google rejects the callback.
To let any Google account sign in without a test-user list, Publish the app to Production on the Audience page. Because our scopes are non-sensitive, publishing needs no Google review and shows no warning.
After pasting, with both servers running (rake run:dev):
- Go to the App login page → click Sign in with Google.
- You should land on Google's consent screen, then bounce back to
/auth/sso_callbackand into the app logged in. - If you get
redirect_uri_mismatch: the registered URI doesn't match byte-for-byte — fix the Console entry or the App'sGOOGLE_REDIRECT_URI.