Notes for Google OAuth reviewers

Everything a reviewer needs to assess this application, in one place. Written for the verification process rather than for prospective customers.

Last updated September 21, 2026

Status

Unified E box is an external OAuth application. It requests one restricted scope and two sensitive scopes, and is therefore subject to OAuth verification and, for the restricted scope, an independent security assessment. We are submitting for that review. We make no claim of being approved, verified, or certified by Google.

1. What the application is

Unified E box is a centralized email-management workspace used by members of our company. The company has a large remote workforce distributed across several countries, and those members use their own personal Gmail accounts rather than Google Workspace accounts. Each member independently connects their own mailbox through Google’s consent flow.

The purpose is to give a member one interface for the mail they already handle: a single list of conversations across their connected mailboxes, search across those conversations, read and unread state that stays consistent with Gmail, and the ability to reply from the correct account. It is a mail client, not a data pipeline.

Why this is not an internal application

Users hold personal Gmail accounts, not accounts in a Google Workspace domain we control, so the application cannot be published as internal. It is external by necessity, and every user passes through the standard consent screen.

2. Scopes and justification

The application requests exactly the three scopes below. This list is generated from the same constant the application uses to build its authorization URL, so it cannot drift from what the consent screen actually shows.

https://www.googleapis.com/auth/gmail.modifyrestricted

Features that require it

  • Fetch the messages and threads that the unified inbox displays.
  • Run an incremental sync so the inbox reflects the mailbox without re-downloading it.
  • Subscribe to mailbox change notifications so new mail appears without constant polling.
  • Apply and remove the UNREAD label when a member marks a conversation read or unread.
  • Apply and remove the STARRED label when a member stars or unstars a conversation, and show stars applied in Gmail itself.
  • Save an email the member is writing as a draft in their Gmail Drafts, update it as they type, and delete it when they send or discard it.
  • Download an attachment on demand when a member opens it.

Methods called

users.getProfileusers.messages.listusers.messages.getusers.messages.attachments.getusers.history.listusers.threads.modifyusers.drafts.createusers.drafts.updateusers.drafts.deleteusers.watchusers.stop
https://www.googleapis.com/auth/gmail.sendsensitive

Features that require it

  • Send a reply or a new message that the member composes in the application.
  • Thread the reply correctly onto the existing conversation in Gmail.

Methods called

users.messages.send
https://www.googleapis.com/auth/userinfo.emailsensitive

Features that require it

  • Identify which mailbox just completed the consent flow, so the resulting credentials are bound to the correct account record.
  • Display the connected address on the Accounts page so a member can tell their mailboxes apart.
  • Prevent the same mailbox from being connected twice.

Methods called

oauth2.userinfo.get
https://www.googleapis.com/auth/userinfo.profilenon-sensitive

Features that require it

  • Show each connected mailbox's own profile photo in the mailbox list, so a member can tell their mailboxes apart at a glance.

Methods called

oauth2.userinfo.get
https://www.googleapis.com/auth/calendar.eventssensitive

Features that require it

  • Show the connected account's upcoming events on the Calendar page, beside its mail.
  • Create an event, and invite guests to it, when a member schedules one from the Calendar page.

Methods called

calendar.events.listcalendar.events.insert

Why gmail.modify rather than a narrower scope

The application needs to read message content and to change read state. Read access alone (gmail.readonly) cannot mark a conversation read, and that state has to stay consistent with Gmail or the two views contradict each other. Since gmail.modify already covers the read access we need, requesting gmail.readonly alongside it would add a second restricted scope for no additional capability, so we do not. We also do not request https://mail.google.com/, which would grant permanent deletion we neither need nor want.

3. How to reproduce each scope’s use

Using a test account we can provide on request, each requested permission maps to a visible action:

  1. Connect a mailbox. From the Accounts page, choose Connect Gmail and complete Google’s consent screen. This exercises userinfo.email, which binds the resulting tokens to the right account.
  2. Watch the inbox populate. The initial sync lists and fetches messages, then registers a change-notification watch. This exercises users.getProfile, users.messages.list, users.messages.get, and users.watch under gmail.modify.
  3. Open a conversation and mark it unread. The same change appears in Gmail, via users.threads.modify adding or removing the built-in UNREAD label.
  4. Star the conversation. The star appears in Gmail too, via users.threads.modify adding or removing the built-in STARRED label.
  5. Start an email and close it unsent. It appears in Gmail’s Drafts, created and kept current with users.drafts.create and users.drafts.update; discarding or sending it removes it with users.drafts.delete.
  6. Open an attachment. The bytes are fetched on demand through users.messages.attachments.get; they are not stored.
  7. Send a reply. Composing and sending exercises users.messages.send under gmail.send, and the reply appears correctly threaded in Gmail.
  8. Disconnect. The token is revoked with Google and the stored credentials are deleted, after which no further Gmail API call succeeds for that mailbox.

4. Data handling summary

  • Stored: message content and metadata for synced mail, attachment metadata, connected-account records, and encrypted OAuth tokens. Detailed on the Gmail integration page.
  • Not stored: attachment contents, Google passwords, and any Google profile field other than the email address and account identifier.
  • Encryption: OAuth tokens are encrypted at rest with AES-256-GCM using a key held outside the database; all transport is over TLS.
  • Isolation: row-level security scopes every query to the caller’s organization, and each API route re-verifies the session server-side.
  • Deletion: self-service disconnect revokes and deletes credentials immediately; verified deletion requests erase stored content within 30 days. See the data deletion page.
  • Limited Use: no advertising, no sale of data, no AI or ML model training on message content, and no human reading of mail outside the narrow exceptions the policy permits.

5. API usage behaviour

After the initial sync, the application does not poll. It relies on Gmail change notifications and then requests only the history since its last known point, so request volume tracks real mailbox activity rather than the number of connected accounts. Watches are renewed before their seven-day expiry. Failures are retried with backoff, and a revoked grant moves the account into a re-authorization state instead of retrying indefinitely.

6. Required pages

All of these are publicly reachable without signing in, and are served from the same domain as the OAuth redirect URI.

7. Contact during review

For anything related to this review, including a demonstration account or a walkthrough recording, contact security@uniebox.vercel.app. We aim to respond within two business days.