Skip to content

Implement Google OAuth flow for Gmail and Calendar publishers #22

@taariq

Description

@taariq

Summary

Implement Google OAuth flow for Gmail and Calendar publishers so users can authenticate without manually fetching tokens.

Problem

Currently, to use the Gmail/Calendar APIs through Seren MCP, users must manually obtain a Google OAuth token (e.g., via OAuth Playground) and pass it in headers. This is a broken UX for production use.

Solution

Leverage Seren's existing token exchange infrastructure to automatically handle Google OAuth:

Architecture

User calls Gmail API (first time)
         │
         ▼
   Token exchange fails (no stored token)
         │
         ▼
   Return "Not authorized" + auth link
         │
         ▼
   User clicks /auth/google
         │
         ▼
   Google consent screen
         │
         ▼
   Callback stores refresh token (keyed by Seren user)
         │
         ▼
   User retries API call
         │
         ▼
   Token exchange succeeds → API call works

Components to Build

1. Google OAuth Authorization Endpoints

GET  /auth/google          - Initiate OAuth flow, redirect to Google
GET  /auth/google/callback - Handle callback, store refresh token

2. Token Exchange Endpoint

POST /token/exchange
  - Receives: Seren API key (via Authorization header)
  - Returns: { "access_token": "...", "expires_in": 3600 }

Called automatically by Seren gateway when token_exchange_url is configured on publisher.

3. Refresh Token Storage

Database table or secure storage:

CREATE TABLE user_google_tokens (
    id UUID PRIMARY KEY,
    seren_user_id TEXT NOT NULL UNIQUE,  -- from X-Agent-Wallet or token claims
    refresh_token_encrypted TEXT NOT NULL,
    scopes TEXT[] NOT NULL,
    created_at TIMESTAMPTZ DEFAULT NOW(),
    updated_at TIMESTAMPTZ DEFAULT NOW()
);

4. Publisher Configuration Update

Update Gmail and Google Calendar publishers with:

{
  "token_exchange_url": "https://google-api.serendb.com/token/exchange",
  "token_exchange_method": "POST",
  "token_exchange_mode": "header",
  "token_cache_ttl_seconds": 3500
}

Google OAuth Scopes

Gmail:

  • https://www.googleapis.com/auth/gmail.readonly
  • https://www.googleapis.com/auth/gmail.send
  • https://www.googleapis.com/auth/gmail.modify

Calendar:

  • https://www.googleapis.com/auth/calendar
  • https://www.googleapis.com/auth/calendar.events

Security Considerations

  • Refresh tokens encrypted at rest
  • HTTPS only for all endpoints
  • CSRF protection on OAuth initiation
  • State parameter validation on callback
  • Scope validation (only request what's needed)

User Experience

  1. User tries to read emails via MCP
  2. Gets clear error: "Google account not connected. Authorize at: https://google-api.serendb.com/auth/google?seren_token=..."
  3. User clicks link, authorizes in browser
  4. Redirected to success page
  5. User retries MCP command - works

Tasks

  • Add OAuth routes (/auth/google, /auth/google/callback)
  • Implement token exchange endpoint (/token/exchange)
  • Add database/storage for refresh tokens
  • Implement token refresh logic
  • Add error handling for "not authorized" state
  • Update publisher configs with token_exchange_url
  • Add tests
  • Document the auth flow for users

References

  • Seren token exchange: serencore/src/services/token_exchange.rs
  • Publisher config fields: token_exchange_url, token_exchange_method, token_exchange_mode, token_cache_ttl_seconds

Taariq Lewis, SerenAI, Paloma, and Volume at https://serendb.com

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions