Skip to content

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).

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 remove supabase.co from the flow entirely.

2. Supabase Auth dashboard

For each project (staging + prod):

  1. Authentication → Providers → Google — enable, paste Client ID + Secret
  2. Authentication → URL configuration
  3. Confirm Site URL matches NEXT_PUBLIC_APP_URL
  4. Redirect URLs must include:
    • https://clinic.theonset.app/auth/callback
    • https://clinic-theonset-app-staging-staging.up.railway.app/auth/callback
    • http://localhost:3000/auth/callback
  5. 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

  1. Register a new clinic owner (email/password) → sign out → Continue with Google (same email) → dashboard
  2. Google with a different email → rejected (google_email_mismatch or google_not_registered)
  3. Practice clinic → invite teammate (seat available) → invitee uses Google (same email) → dashboard, status active
  4. Invite when at seat cap → 402 from team API
  5. 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