Skip to content

Latest commit

 

History

History
96 lines (79 loc) · 5.51 KB

google-oauth-verification.md

File metadata and controls

96 lines (79 loc) · 5.51 KB

Google OAuth Verification — Submission Reference

Everything needed to take the OAuth consent screen from Testing to Published, and to answer the questions Google's reviewers ask. Keep this document in sync with src/server/integrations.ts, the single source of truth for scopes in code.

Scopes requested

Scope Classification Why we need it Features it powers
https://www.googleapis.com/auth/gmail.modify Restricted Read messages and change mailbox state. Strictly narrower than mail.google.com; supersedes gmail.readonly, which is therefore not requested. Inbox list, message view, search, AI priority triage, archive / star / mark read / trash
https://www.googleapis.com/auth/gmail.send Restricted Send mail the user composes. Grants no read access. Compose, reply, forward
https://www.googleapis.com/auth/calendar.events Sensitive View and manage events only — deliberately not the full auth/calendar scope (no calendar list / ACL / settings access). Calendar view, event create/update/delete, invitations, focus timeline, event push notifications

Identity scopes (openid, email, profile) are requested at sign-in only.

Where scopes are requested in code (the complete list):

  1. src/app/_components/auth/integration-connect.tsx — authClient.linkSocial({ scopes }), using GOOGLE_SCOPES from src/server/integrations.ts. Gmail and Calendar are requested separately, only when the user clicks the respective Connect button (incremental authorization).
  2. src/app/_components/auth/social-buttons.tsx — Google sign-in, identity only.

Legacy grants (gmail.readonly, full auth/calendar) from earlier builds are still recognized by getIntegrationStatus so existing users keep working, but are never requested again.

Limited Use compliance summary

(Reviewers ask for this; it is also stated on /privacy and the homepage.)

  • Google user data is used only to provide user-facing features: inbox display, triage, search, composing/sending, and calendar scheduling.
  • No advertising use, no sale of data, no human access except with explicit user consent, for security, or as required by law.
  • The mailbox is not synced or copied to our servers. Messages are fetched from the Gmail API per request. The only derived data stored is a per-message priority/category label (no message content) in email_classification.
  • AI features send relevant excerpts to the Google Gemini API at the user's direction, solely to produce the requested output; not used to train generalized models. Disclosed in the privacy policy.
  • OAuth tokens are stored encrypted (Better Auth account table plus Corsair's KEK-encrypted credential store) and deleted on disconnect.

User data controls (reviewers test these)

  • /settings — shows exactly which permissions are granted; Disconnect Google & revoke access calls https://oauth2.googleapis.com/revoke and deletes tokens, push channels, and triage labels (account.disconnectGoogle in src/server/api/routers/account.ts).
  • Delete account — same revocation plus full deletion of the user row and all cascaded data, and explicit purge of Corsair tenant rows (account.deleteAccount).
  • The privacy policy also links Google's own permissions page.

Pre-submission checklist

Console: APIs & Services → OAuth consent screen in the project that owns the OAuth client.

  • App domain ownership verified in Google Search Console for the production domain (the one in BETTER_AUTH_URL).
  • Homepage — production / (public, describes the app, links the privacy policy in the footer).
  • Privacy policy URL — production /privacy.
  • Terms of service URL — production /terms.
  • Authorized redirect URI — <BETTER_AUTH_URL>/api/auth/callback/google.
  • Authorized JavaScript origin — <BETTER_AUTH_URL>.
  • App name, logo (120×120), and support email set; logo triggers brand verification.
  • Scope justifications — paste the table above, one justification per scope, naming the in-product feature.
  • Demo video (YouTube, unlisted is fine) showing: the OAuth consent screen with your production client, connecting Gmail and Calendar separately, each scope being exercised in the UI (inbox + archive for gmail.modify, sending for gmail.send, event creation for calendar.events), and the disconnect flow in /settings.
  • Because gmail.modify and gmail.send are restricted scopes, expect the security assessment (CASA Tier 2) for public launch. Budget for an annual third-party assessment once over 100 users.
  • Enable the Gmail API and Google Calendar API in the project.
  • Move publishing status from Testing to In production and submit for verification.

Notes that prevent rejection

  • The consent screen domain, BETTER_AUTH_URL, homepage, privacy, and terms must all live on the same verified domain.
  • The privacy policy must mention Google user data specifically (ours does: see "How we use Google user data" on /privacy) and include the Limited Use disclosure.
  • Don't request scopes the demo video doesn't show being used — reviewers reject on unused scopes. Our request set is exactly what the UI uses.
  • Keep using incremental auth (separate Gmail / Calendar connects); Google explicitly recommends it and it reduces review friction.