name: google-platform-integration
description: Guide therefore Google account integration, OAuth authentication flows, vault-gated credential handling, Gmail or Calendar or Contacts API work, multi-account behavior, scope changes, and related Tauri command updates. Use when working in src/features/google/, Google-aware mail/calendar/contacts code, components/modules/settings/providers/AccountProvider*, or backend Google auth/domain files under src-tauri/src/commands/ and src-tauri/src/services/google_auth_service*.
Google platform integration
Mission
Keep therefore's Google integration aligned across frontend auth orchestration, backend-owned Google API access, and vault-protected credential storage.
Preserve these product contracts:
- Raw Google access tokens do not cross the IPC boundary in production builds. Frontend code uses metadata snapshots only.
- Desktop token reads and writes are vault-gated.
- Feature modules import the Google auth facade, not the state machine or vault flow directly.
- Tasks are local-only. There is no active Google Tasks API integration.
Start here
- Read the authoritative docs before editing:
docs/architecture/google-platform-integration.mddocs/technical/capability-contracts.mddocs/testing/google-oauth-verification-plan.mdsrc/features/google/README.md
- Map the change to the owning layer before touching code.
- Check current code paths, not just docs. If docs and code disagree, follow code for immediate correctness and update the docs in the same change.
- Treat multi-account stability, vault behavior, and token ownership as high-risk invariants.
Layer map
Frontend auth layers
src/features/google/unifiedAuthService.tsPublic facade for feature modules. PreferunifiedGoogleAuth.src/features/google/unifiedAuthStateMachine.tsSingleton that drives PKCE, browser launch, callback handling, code exchange, migration, and token snapshot access.src/features/google/unifiedAuthVaultFlow.tsVault unlock, create, lock, reset, password change, and recovery flow. Desktop-only branches must stay behindisTauriRuntime().src/features/google/unifiedAuthPkceFlow.tsandsrc/features/google/unifiedAuthPkceSession.tsPKCE session lifecycle, storage, timeout, and validation.src/features/google/unifiedAuthApi.tsThe only frontend IPC layer for Google auth and vault commands. UsesafeInvokefor writes andsafeInvokeReadOnlyfor reads.src/features/google/unifiedAuthTypes.tsCanonical types, Google auth error classes, and Google scope constants.src/features/google/unifiedAuthVaultFlow.tsandsrc/features/google/unifiedAuthTypes.tsAuto-unlocked saved-credentials compatibility shim plus auth/vault error types.
Backend ownership
src-tauri/src/services/google_auth_service.rsOwns token refresh and auth lifecycle helpers.src-tauri/src/services/google_auth_service/account_lifecycle.rsReuses an existing refresh token when a re-auth response omitsrefresh_token.src-tauri/src/commands/unified_google.rsOAuth start and exchange plus loopback plumbing. Redirects usehttp://127.0.0.1:{port}, notlocalhost.src-tauri/src/commands/google_calendar.rsCalendar domain command surface on top of shared auth helpers.src-tauri/src/services/gmail/message_service_simple/Central Gmail API ownership. Commands delegate here for refresh and rate-limit handling.src-tauri/src/services/encrypted_secrets_store/AES-256-GCM + Argon2id encrypted vault with rolling backup support.
Related feature modules
src/features/mail/Gmail UI and data helpers. Renderer code must not refresh tokens or use a direct HTTP Gmail transport for mutations.src/features/calendar/Calendar sync, views, timeblocks, and tasks rail display. Task timeblocks are calendar projections, not Google Tasks API data.src/features/contacts/Google People or Contacts fetch, SQLite cache, frequency tracking, and compose autocomplete.src/features/tasks/Local-only SQLite tasks. Do not treat this as a Google integration surface.
Hard boundaries
- Never bypass
vaultFlow.withVault(...)for desktop token operations. - Never import
unifiedAuthStateMachine.tsorunifiedAuthVaultFlow.tsfrom mail, calendar, contacts, or other feature modules. - Never call Tauri commands directly from feature modules. Route them through
unifiedAuthApi.ts. - Never move raw access tokens into renderer state, persisted stores, or feature-level caches.
- Never add Google Tasks scopes or Tasks API calls to active auth flows.
- Never reset the active Mail or Calendar account implicitly during re-auth or scope extension.
Workflows
Changing OAuth or vault flow
- Start at the public boundary:
unifiedAuthService.tsunifiedAuthStateMachine.tsunifiedAuthVaultFlow.tsunifiedAuthApi.ts
- Preserve these invariants:
- Validate PKCE session state before code exchange.
- Log and ignore stale or duplicate callbacks instead of crashing the flow.
- Keep loopback redirect handling on
127.0.0.1. - Treat
VaultPasswordCancelledErroras a graceful exit, not a fatal crash. - Keep migration calls idempotent via
runMigration()during initialize paths when storage shape changes.
- Audit both frontend and backend when auth semantics change. Do not patch only one side of the boundary.
Changing Gmail, Calendar, or Contacts behavior
- Keep feature modules on the facade or existing bridge surfaces.
- Put new Google API ownership in the backend service or command layer, not in the renderer.
- For Gmail changes, prefer the existing message service under
src-tauri/src/services/gmail/message_service_simple/. - For Calendar changes, keep task timeblock behavior framed as Calendar integration.
- For Contacts changes, preserve SQLite cache and frequency-tracking behavior.
Changing scopes or account-selection behavior
- Add new scopes to
GOOGLE_SCOPESinunifiedAuthTypes.ts. - Only add a scope to
getAllDefaultScopes()when the feature truly requires it during first sign-in. - Keep incremental scope extension aligned with
components/modules/settings/providers/AccountProvider*andsrc/features/settings/googleScopes.ts. - Preserve active account IDs for Mail and Calendar across permission extensions and re-auth.
- Confirm new scopes are declared in both frontend descriptors and backend allowlists.
Changing Tauri command surfaces
- Add or adjust the command in
src-tauri/src/commands/. - Add or adjust the frontend call in
src/features/google/unifiedAuthApi.ts. - Keep the command thin and delegate Google API logic to the backend service layer.
- Update typed errors or request or response shapes in
unifiedAuthTypes.tswhen the frontend contract changes.
Current drift and open gaps to verify intentionally
src/features/google/unifiedAuthTypes.tsstill definesGOOGLE_SCOPES.TASKSandGOOGLE_SCOPES.TASKS_READONLY, butgetAllDefaultScopes()no longer includesGOOGLE_SCOPES.TASKS. Treat any future attempt to re-add Tasks to the default auth flow as intentional scope expansion that must be justified against the local-only Tasks architecture, not as restoring old behavior.forceConsentis a convention, not a guarded invariant. New auth entry points can accidentally churn refresh tokens if they force consent by default.- Incremental auth exists in the Settings account flow, but the architecture backlog still calls out broader incremental-scope guidance as incomplete.
- Playwright or E2E OAuth coverage is still incomplete. Do not claim full end-to-end auth coverage without adding it.
- Vault-only security assertions and background refresh scheduler consolidation are still listed as open work in the architecture doc.
Verification
Use the narrowest commands that cover the touched Google surface.
- Frontend auth flow:
npx vitest run tests/unifiedAuthService.test.ts src/features/google/unifiedAuthPkceFlow.test.ts src/features/google/__tests__/unifiedAuthVaultFlow.test.ts
- Workspace persistence or account-selection behavior:
npx vitest run tests/googleWorkspaceStorage.test.ts tests/googleWorkspacePersistence.test.ts src/features/settings/state/googleWorkspaceAccountMutations.test.ts src/features/settings/__tests__/googleWorkspacePreferences.test.ts
- AccountProvider or scope-selection changes:
npx vitest run tests/unifiedAuthService.test.ts tests/googleWorkspaceStorage.test.ts
- Rust auth backend:
cargo test google_auth --manifest-path src-tauri/Cargo.tomlcargo test GoogleAuthService --manifest-path src-tauri/Cargo.toml
- Contacts backend:
cargo test contacts --manifest-path src-tauri/Cargo.toml
Run npm run type-check when the change touches TypeScript-facing contracts. Update the architecture doc or verification plan in the same slice when behavior or required checks change.