Live Gmail connect
MAIL-254 / MAIL-255 / MAIL-256 add the Duckbill™ product path for connecting
multiple Gmail identities. A signed-in user starts Google OAuth from
/accounts; the callback persists one connected_accounts row per stable
Google identity and stores access and refresh tokens only as encrypted
provider_tokens.
Product path
- Sign in to Duckbill and open
/accounts. - Select Connect Gmail. The browser requests
/api/providers/gmail/start. - Google receives a PKCE authorization request for
openid,email, andgmail.readonly. - Google returns to
/connect/gmail/callback. - The server exchanges the code, reads the Google profile, upserts by
(user, provider, provider identity), encrypts tokens, and returns only redacted account health. - The browser returns to
/accounts, where each authorized Gmail identity is a separate row.
Repeating the flow with another Google identity creates another Gmail account for the same Duckbill user. Reauthorizing the same Google identity updates that account rather than duplicating it.
Host configuration
Set these names independently on preview and production. Never commit values.
| Variable | Purpose |
|---|---|
GOOGLE_CLIENT_ID | Google OAuth web client |
GOOGLE_CLIENT_SECRET | Google OAuth client secret |
GMAIL_REDIRECT_URI | Exact callback URL, such as https://duckbill-dev.jasonkoch.io/connect/gmail/callback |
The common DATABASE_URL, TOKEN_ENCRYPTION_KEY, and SESSION_SECRET
requirements still apply. Gmail routes return 503 until all required names are
configured.
Safety and isolation
The authorization request rejects full mail.google.com, gmail.send, and
gmail.compose scopes. ENABLE_SEND and ENABLE_DELETE remain false.
Provider tokens never enter ia_session, API responses, Jira, logs, or docs.
MAIL-257 keeps account loops independent through
runIndependentAccountLoops. An injected Gmail provider failure is reported
for that account while Graph processing continues.
