Google Sign-In — Onset Clinic Portal¶
Login-only Google OAuth for the clinic portal. Google does not create new clinic accounts — users must register (owners) or be invited (team) first with the same email as their Google account.
Behavior¶
| User type | Requirement | Google login |
|---|---|---|
| New owner | Complete email/password signup + onboard first | Allowed after practitioner row exists |
| Team member | Invited on Practice plan with an available seat | Allowed after invite (matching email) |
| Random Google account | No practitioner row | Rejected at /auth/callback |
Post-auth flow: src/lib/clinic-auth-complete.ts → activates invited teammates, sets account_scope: clinic_portal.
1. Google Cloud Console¶
Create (or reuse) an OAuth 2.0 Web application client.
Authorized JavaScript origins
| Environment | Origin |
|---|---|
| Production | https://clinic.theonset.app |
| Staging | https://clinic-theonset-app-staging-staging.up.railway.app |
| Local | http://localhost:3000 |
Authorized redirect URIs (Supabase Auth callback — not the app callback):
| Supabase project | Redirect URI |
|---|---|
Onset-staging (lzpyfohgfdohrtlamzek) |
https://lzpyfohgfdohrtlamzek.supabase.co/auth/v1/callback |
Onset prod (emxrmjysvxeboavhatry) |
https://emxrmjysvxeboavhatry.supabase.co/auth/v1/callback |
Copy Client ID and Client secret for each Supabase project (one Google client can list both redirect URIs).
OAuth consent screen (branding)¶
Google shows this screen during Continue with Google. Brand it as Onset Clinic so users see your app name and logo instead of a generic Google prompt.
Where: Google Cloud Console → APIs & Services → OAuth consent screen (same project as your OAuth client).
App information
| Field | Value |
|---|---|
| App name | Onset Clinic Portal |
| User support email | Your team inbox (e.g. support@theonset.app) |
| App logo | Upload docs/assets/google-oauth-app-logo.png (120×120 PNG) |
App domain
| Field | Value |
|---|---|
| Application home page | https://clinic.theonset.app |
| Application privacy policy link | https://clinic.theonset.app/privacy |
| Application terms of service link | https://clinic.theonset.app/terms |
| Authorized domains | theonset.app (no https://) |
Developer contact information: add at least one email Google can reach for OAuth verification notices.
Scopes: Supabase Google auth uses basic OpenID scopes (email, profile, openid). No extra sensitive scopes are required for clinic login.
Publishing status
- Testing — only accounts listed under Test users can sign in; fine for staging QA.
- In production — required before real clinic users use Google login at scale. Google may review the app if you request sensitive scopes; basic profile/email usually passes quickly when privacy/terms URLs are live.
After saving, sign out and run Continue with Google again — the consent screen should show Onset Clinic Portal, your logo, and links to the clinic site.
Note: Google still routes OAuth through Supabase (
*.supabase.co) in the redirect chain. Branding the consent screen improves trust; a fully custom auth domain (Supabase custom domain add-on) is the next step if you want to removesupabase.cofrom the flow entirely.
2. Supabase Auth dashboard¶
For each project (staging + prod):
- Authentication → Providers → Google — enable, paste Client ID + Secret
- Authentication → URL configuration
- Confirm Site URL matches
NEXT_PUBLIC_APP_URL - Redirect URLs must include:
https://clinic.theonset.app/auth/callbackhttps://clinic-theonset-app-staging-staging.up.railway.app/auth/callbackhttp://localhost:3000/auth/callback
- Authentication → Providers → (settings) — enable Automatic linking for matching verified emails so Google sign-in attaches to existing email/password or invite auth users instead of creating duplicates.
Apply staging auth templates (includes redirect allow-list):
SUPABASE_ACCESS_TOKEN=sbp_xxx \
PROJECT_REF=lzpyfohgfdohrtlamzek \
SITE_URL=https://clinic-theonset-app-staging-staging.up.railway.app \
URI_ALLOW_LIST="https://clinic-theonset-app-staging-staging.up.railway.app/auth/callback,http://localhost:3000/auth/callback" \
./scripts/supabase/apply-auth-email-templates.sh
Repeat for prod with PROJECT_REF=emxrmjysvxeboavhatry and SITE_URL=https://clinic.theonset.app.
3. App code (already implemented)¶
- Login page: Continue with Google →
signInWithOAuth→/auth/callback /auth/callback: exchange code →completeClinicAuth→ dashboard or sign-out + error/auth/confirm?type=invite: same completion step after OTP verify- Team invite: seat cap enforced before
inviteUserByEmail
No extra Railway env vars — Google credentials live in Supabase only.
4. Test checklist¶
Staging¶
- Register a new clinic owner (email/password) → sign out → Continue with Google (same email) → dashboard
- Google with a different email → rejected (
google_email_mismatchorgoogle_not_registered) - Practice clinic → invite teammate (seat available) → invitee uses Google (same email) → dashboard, status
active - Invite when at seat cap → 402 from team API
- Password login still works after onboarding
Production¶
Repeat after enabling Google provider on prod Supabase project.
Error codes (login page)¶
| Query param | Meaning |
|---|---|
google_not_registered |
No practitioner row — register or get invited |
google_email_mismatch |
Google email ≠ clinic account email |
clinic_access_required |
Generic auth/setup failure |