Gmail Integration¶
The Gmail integration enables WhiteLotusAI to retrieve, search, and analyze email data through conversational requests. The inspected implementation also contains email-writing and mailbox-modification capabilities, which must be restricted before the integration can be approved for strict read-only operation.
Documentation status: Source-reviewed. End-to-end behavior, authorization boundaries, and read-only enforcement remain to be verified.
Read-only security requirement
The current implementation includes operations that send or modify email. Do not treat the integration as read-only merely because a request originates from a conversational interface or because a tool requests confirmation. Enforce the policy at the tool registry, dispatch layer, and integration API.
1. Architecture and components¶
The Gmail integration spans the chat plugin, integration-service handlers, and Gmail client. The chat plugin interprets conversational requests and dispatches operations to the integration service, where credentials and Gmail API requests are handled.
flowchart TD
U["User request"] --> P["Email chat plugin"]
P --> R["Conversational response"]
P --> Q["Intent and query processing"]
Q --> T["Tool selection and dispatch"]
T -->|HTTP request| I["Integration service"]
I --> A["User-specific connection and token resolution"]
A --> C["Gmail client"]
C --> G["Google Gmail API"]
G --> C
C --> I
I --> P
A -.-> S["OAuth and token storage"]
S -.-> C
classDef app fill:#e8eaf6,stroke:#5c6bc0,color:#202124
classDef service fill:#e0f2f1,stroke:#00897b,color:#202124
classDef external fill:#fff3e0,stroke:#ef8c00,color:#202124
class P,Q,T,R app
class I,A,C,S service
class G external
The diagram represents the documented logical flow, not proof that every path is registered or reachable in the deployed application.
| Component | Source location | Responsibility |
|---|---|---|
| Email chat plugin | chat/package/app/plugins/email/plugin.py |
Intent detection, natural-language query processing, tool definitions, and dispatch |
| Integration handlers | integrations/package/app/handlers/integration_handlers.py |
OAuth lifecycle, user-token resolution, HTTP routes, and request handling |
| Gmail client | integrations/package/app/managers/gmail_client.py |
Gmail API requests, retrieval, search, attachment processing, token refresh, and mailbox operations |
| Additional Gmail handlers | integrations/package/app/handlers/gmail_handlers.py |
Additional OAuth, inbox, search, and send handlers; registration and reachability require verification |
The chat plugin constructs requests using INTEGRATIONS_SERVICE_URL and the /api/integrations-svc base path.
2. Supported capabilities¶
2.1 Read operations¶
The chat plugin defines the following read-oriented tools:
| Tool | Purpose |
|---|---|
gmail_query |
Interprets natural-language requests and searches Gmail |
search_emails |
Searches for matching email messages |
read_inbox |
Retrieves inbox messages |
get_inbox_stats |
Retrieves inbox statistics |
get_email |
Retrieves an individual message |
get_thread |
Retrieves a conversation thread |
read_drafts |
Inspects existing drafts |
list_attachments |
Lists message attachments |
download_attachment |
Retrieves an attachment |
list_labels |
Lists Gmail labels |
The plugin includes parsing for sender and recipient filters, subjects, dates, categories, attachments, message states, and native Gmail search operators.
Actual results depend on query interpretation, Gmail API behavior, granted permissions, and the connected account.
2.2 Write and mailbox-modification operations¶
The source also defines operations that can change mailbox state or send messages.
| Operation | Tool or capability | Effect | Risk |
|---|---|---|---|
| Create a draft | draft_email |
Creates a draft | Write |
| Send an email | send_email |
Sends a message | External side effect |
| Reply | reply_email |
Sends a reply | External side effect |
| Forward | forward_email |
Forwards a message | External side effect |
| Modify labels | modify_labels |
Adds or removes labels | Write |
| Mark as read | mark_read |
Removes unread state | Write |
| Mark as unread | mark_unread |
Adds unread state | Write |
| Archive | archive_email |
Removes the inbox label | Write |
| Star | star_email |
Adds or removes the starred label | Write |
| Move to Trash | trash_email |
Moves a message to Trash | Destructive |
The plugin metadata marks sending, drafting, replying, and forwarding as confirmation-requiring operations. Trash is categorized as destructive and requires confirmation. Some other modification tools do not declare confirmation requirements in their definitions.
Confirmation is not an authorization boundary
Confirmation prompts are not a substitute for enforcing a read-only policy. When strict read-only mode is required, write-capable operations must be denied even if a caller requests them or a confirmation flag is present.
Required policy: Disable or block every write-capable operation across tool registration, tool dispatch, and integration API routes. Verify the actual enforcement with negative tests before declaring compliance.
3. OAuth authentication¶
3.1 Authorization flow¶
The primary Gmail OAuth implementation is located in integrations/package/app/handlers/integration_handlers.py.
sequenceDiagram
autonumber
participant F as Frontend
participant I as Integration service
participant R as Redis
participant G as Google OAuth
participant U as User service
F->>I: Start authorization with application JWT
I->>I: Decode JWT and identify user
I->>I: Generate state and PKCE verifier/challenge
I->>R: Store state and verifier with TTL
I-->>F: Redirect to Google authorization
F->>G: Authorize requested scopes
G-->>I: Callback with code and state
I->>R: Retrieve and consume stored state
I->>G: Exchange code using PKCE verifier
G-->>I: OAuth tokens
I->>I: Store token data server-side
I->>U: Update connection status where supported
I-->>F: Redirect with connection status
The documented implementation follows these steps:
- The frontend initiates Gmail authorization and supplies the application JWT.
- The integration handler decodes the JWT to identify the user.
- The handler generates a PKCE verifier, an S256 challenge, and a random state value.
- The verifier and user association are stored in Redis with a ten-minute expiration.
- The browser is redirected to Google's OAuth authorization page.
- Google returns an authorization code and state to the callback.
- The handler retrieves and deletes the stored state entry and exchanges the code using the PKCE verifier.
- The handler requires a refresh token and stores token data server-side.
- The user's Gmail connection is marked active where the connection update succeeds.
- The browser is redirected to the frontend with a connection-status indicator.
The success redirect is not intended to include token values. Verify this behavior for error redirects and every registered OAuth callback as well.
3.2 Requested OAuth scopes¶
| Scope | Purpose | Read-only suitability |
|---|---|---|
openid |
OpenID Connect identity | Compatible |
https://www.googleapis.com/auth/userinfo.email |
Read the user's email identity | Compatible with identity lookup |
https://www.googleapis.com/auth/gmail.readonly |
Read Gmail data | Suitable for read-only access |
https://www.googleapis.com/auth/gmail.compose |
Create and manage drafts and compose messages | Broader than required for strict reading |
https://www.googleapis.com/auth/gmail.modify |
Read and modify mailbox state | Broader than required for strict reading |
The primary implementation requests all five scopes. The compose and modify scopes are broader than a strict read-only integration requires.
Scope reduction requires migration planning
Reducing OAuth scopes may require renewed consent and reauthorization of existing connections. Verify the resulting granted scopes and token behavior rather than assuming a code change automatically narrows existing grants.
3.3 User-specific token resolution¶
The inspected integration handler:
- Checks the user's Gmail connection status.
- Retrieves stored token data for the requesting user.
- Returns token information for downstream Gmail API calls.
- Returns an unavailable-token result when the connection is inactive or token lookup fails.
The Gmail client can reuse a valid access token and request a replacement from Google's OAuth token endpoint when necessary. It also attempts to persist refreshed token data through the user service.
A global GMAIL_REFRESH_TOKEN fallback exists in some code paths. Until its use is verified and appropriately restricted, strict per-user isolation must not be assumed.
4. API reference¶
The routes below are documented from integrations/package/app/handlers/integration_handlers.py. Their effective prefix is /api/integrations-svc.
Routing caveat: The separate
gmail_handlers.pymodule contains additional handlers. Confirm router registration and effective reachability in the deployed application before treating this table as an exhaustive API inventory.
4.1 OAuth and authentication¶
| Method | Endpoint | Purpose |
|---|---|---|
GET |
/api/integrations-svc/gmail/auth |
Starts Gmail OAuth |
GET |
/api/integrations-svc/gmail/callback |
Handles the OAuth callback |
4.2 Read endpoints¶
| Method | Endpoint | Purpose |
|---|---|---|
GET |
/api/integrations-svc/gmail/inbox |
Retrieves inbox messages |
GET |
/api/integrations-svc/gmail/search |
Searches messages |
GET |
/api/integrations-svc/gmail/stats |
Retrieves mailbox statistics |
GET |
/api/integrations-svc/gmail/health |
Exposes a Gmail health endpoint |
GET |
/api/integrations-svc/gmail/message/{message_id} |
Retrieves a message |
GET |
/api/integrations-svc/gmail/thread/{thread_id} |
Retrieves a conversation |
GET |
/api/integrations-svc/gmail/drafts |
Lists existing drafts |
GET |
/api/integrations-svc/gmail/labels |
Lists Gmail labels |
GET |
/api/integrations-svc/gmail/label/{label} |
Retrieves label statistics |
GET |
/api/integrations-svc/gmail/message/{message_id}/attachments |
Lists message attachments |
GET |
/api/integrations-svc/gmail/message/{message_id}/attachment/{attachment_id} |
Downloads an attachment |
4.3 Write endpoints¶
These routes must be denied in strict read-only mode.
| Method | Endpoint | Effect |
|---|---|---|
POST |
/api/integrations-svc/gmail/send |
Sends an email |
POST |
/api/integrations-svc/gmail/draft |
Creates a draft |
POST |
/api/integrations-svc/gmail/reply |
Sends a reply |
POST |
/api/integrations-svc/gmail/forward |
Forwards a message |
POST |
/api/integrations-svc/gmail/labels/modify |
Modifies labels |
POST |
/api/integrations-svc/gmail/message/{message_id}/read |
Marks a message as read |
POST |
/api/integrations-svc/gmail/message/{message_id}/unread |
Marks a message as unread |
POST |
/api/integrations-svc/gmail/message/{message_id}/archive |
Archives a message |
POST |
/api/integrations-svc/gmail/message/{message_id}/trash |
Moves a message to Trash |
POST |
/api/integrations-svc/gmail/message/{message_id}/star |
Stars or unstars a message |
The existence of a route does not establish that it is appropriately authenticated, authorized, or protected by the read-only policy.
5. Configuration and credential handling¶
The following settings are referenced by the inspected implementation. Confirm their authoritative definitions, required values, and defaults against the repository's configuration and deployment files.
| Setting | Purpose |
|---|---|
GMAIL_CLIENT_ID |
Google OAuth client identifier |
GMAIL_CLIENT_SECRET |
OAuth client secret, where required by the client configuration |
GMAIL_REDIRECT_URI |
Callback URI registered with Google |
GMAIL_REFRESH_TOKEN |
Global refresh-token fallback in some code paths |
GMAIL_SENDER_EMAIL |
Sender address used to construct outgoing messages |
JWT_SECRET_KEY |
Application JWT decoding |
JWT_ALGORITHM |
JWT algorithm configuration |
INTERNAL_SECRET |
Authentication between trusted internal services |
FRONTEND_URL |
Destination for OAuth callback redirects |
INTEGRATIONS_SERVICE_URL |
Base URL used by the chat plugin |
USER_SERVICE_URL |
User-service URL used to persist refreshed credentials |
5.1 Security requirements¶
- Never commit OAuth client secrets, access tokens, or refresh tokens to version control.
- Keep production credentials in the approved secret-management system.
- Never publish secrets in documentation, logs, screenshots, or issue reports.
- Enforce user-specific credential lookup and authorization on every request.
- Avoid shared global refresh tokens when strict per-user isolation is required.
- Review requested OAuth scopes and remove unnecessary write permissions.
- Redact sensitive provider responses and prevent email content from leaking into logs.
- Restrict internal-service endpoints to authenticated, authorized callers.
5.2 Example environment configuration¶
The following is a template, not a complete deployment configuration. Supply values through the approved secrets and environment-management mechanism.
GMAIL_CLIENT_ID=<google-oauth-client-id>
GMAIL_CLIENT_SECRET=<managed-secret>
GMAIL_REDIRECT_URI=<registered-callback-uri>
JWT_SECRET_KEY=<managed-application-secret>
JWT_ALGORITHM=<configured-jwt-algorithm>
INTERNAL_SECRET=<managed-internal-service-secret>
FRONTEND_URL=<frontend-base-url>
INTEGRATIONS_SERVICE_URL=<integration-service-base-url>
USER_SERVICE_URL=<user-service-base-url>
Do not place actual credentials in the documentation. The global refresh-token fallback and sender-address settings are intentionally omitted from this baseline template because their necessity and intended production use must first be verified.
6. Query processing and result handling¶
The email plugin translates conversational requests into Gmail search queries instead of passing every natural-language request directly to the provider.
| Query category | Examples of supported intent |
|---|---|
| Sender and recipient | Messages from a person or sent to a particular address |
| Subject and phrases | Subject matches and exact-phrase searches |
| Date range | Recent messages or messages from an explicit period |
| Categories and labels | Category-specific or label-specific searches |
| Message state | Read, unread, or starred messages |
| Attachments | Messages with attachments or common file types |
| Conversations | Threads and related messages |
| Aggregation | Message counts and inbox statistics |
| Native query syntax | Gmail search operators |
The plugin also preserves message and thread references in response-processing logic so later conversational requests can refer to previously retrieved emails.
These are documented implementation capabilities, not a guarantee that every natural-language request will be interpreted correctly. Regression tests should cover ambiguous phrasing, empty results, date boundaries, and provider-specific query behavior.
7. Error handling and observability¶
The inspected implementation uses HTTP status checks, exceptions, and logging around Gmail API requests and OAuth processing. The chat plugin also handles integration-service errors and includes a health-check method that requests a small inbox result.
| Failure category | Recommended verification |
|---|---|
| Missing OAuth configuration | Fail safely without exposing secret values |
| Invalid, expired, or revoked credentials | Return an appropriate error and handle reconnection |
| OAuth callback or token-exchange failure | Validate state handling and redact provider responses |
| Missing or inactive connection | Deny access without falling back to another user's credentials |
| Gmail API authorization failure | Distinguish permission failures from general upstream errors |
| Network timeout or upstream failure | Verify timeout behavior and bounded retries |
| Attachment retrieval failure | Validate ownership, identifiers, and error responses |
| Token persistence failure | Test refresh success followed by persistence failure |
| Invalid identifiers or query parameters | Reject malformed inputs and out-of-range values |
Logging requirements: Do not expose access tokens, refresh tokens, authorization codes, message bodies, or unnecessary provider response details. Review existing logging paths before production use.
A successful HTTP response or a health endpoint response alone does not establish full integration readiness.
8. Security findings and remediation priorities¶
The following findings are based on source inspection. They are not claims that fixes have been implemented or that tests have passed.
| ID | Finding | Required action | Priority |
|---|---|---|---|
GMAIL-01 |
Write-capable tools and endpoints are present | Enforce read-only restrictions at registration, dispatch, and API boundaries | Critical |
GMAIL-02 |
OAuth requests include compose and modify scopes | Establish the minimum scope set and plan reauthorization | High |
GMAIL-03 |
Some paths use a global refresh-token fallback | Verify user isolation and eliminate unsafe cross-account fallback | Critical |
GMAIL-04 |
A separate gmail_handlers.py contains additional handlers |
Audit route registration and remove or secure duplicate paths | High |
GMAIL-05 |
OAuth failure paths may log provider response text | Redact sensitive response details and audit logs | High |
GMAIL-06 |
Some request parameters need boundary validation | Test limits, malformed inputs, and pagination | High |
GMAIL-07 |
Refreshed-token persistence can fail after refresh | Define safe recovery and concurrent-refresh behavior | High |
GMAIL-08 |
OAuth state and PKCE depend on temporary storage | Test expiration, replay, invalid callbacks, and multi-instance behavior | High |
GMAIL-09 |
Authentication spans the plugin and integration service | Test user headers, internal secrets, and authorization boundaries | Critical |
GMAIL-10 |
Health checks may not establish complete readiness | Test disconnected accounts, expired tokens, and dependency failures | Medium |
GMAIL-11 |
Natural-language parsing has multiple patterns and fallbacks | Build a representative regression suite | Medium |
GMAIL-12 |
Source inspection does not establish end-to-end reliability | Run controlled integration tests before release | High |
Priorities indicate suggested remediation order, not a completed security assessment or a formal risk acceptance.
9. Verification checklist¶
Use this checklist during implementation review and release validation. Mark items complete only when supported by test evidence.
OAuth and credential security¶
- OAuth consent and callback work with a dedicated test account.
- PKCE state expires and can be consumed only once.
- Invalid, missing, expired, and replayed state values fail safely.
- Credentials remain server-side and never appear in frontend responses.
- User A cannot retrieve User B's messages, tokens, or connection data.
- Missing connections and invalid internal-service credentials fail closed.
- Token refresh, persistence failures, and concurrent refreshes are tested.
- OAuth redirects and logs do not expose secrets or authorization codes.
Read-only enforcement¶
- Every write-capable tool is disabled or rejected.
- Direct requests to every write endpoint are denied.
- Read-only enforcement cannot be bypassed by supplying confirmation metadata.
- No alternate or duplicate route bypasses the policy.
- OAuth scopes match the approved read-only behavior.
- Negative tests confirm that no mailbox state or message is changed.
Functional and operational validation¶
- Inbox, search, message, thread, and label retrieval return expected results.
- Attachment listing and downloads enforce user authorization.
- Result limits, identifiers, and query parameters are validated.
- Natural-language search regression tests cover dates, senders, phrases, attachments, ambiguity, and empty results.
- Error responses and logs do not expose secrets or unnecessary message content.
- Health checks reflect the readiness criteria adopted for deployment.
- End-to-end tests pass against the intended deployment configuration.
Release acceptance criteria
Approve the integration for strict read-only use only after the write paths are demonstrably blocked, per-user isolation is tested, OAuth scopes are reviewed, and the relevant end-to-end tests pass. Documentation completion alone is not sufficient evidence.
10. Source of truth and change management¶
The source repository remains authoritative for implementation behavior. Review this page whenever the Gmail plugin, OAuth scopes, token storage, integration routes, configuration, or read-only policy changes.
Keep the following distinctions explicit during future updates:
- Implemented: Supported by source inspection.
- Verified: Confirmed by reproducible tests or deployment evidence.
- Required: A security, operational, or product acceptance criterion that may not yet be implemented.
Do not document a capability as a security guarantee until its enforcement has been verified and tested.