Skip to main content

Google Services Integration

Integrate Google Calendar, Gmail, and Google Chat with your applications through OAuth 2.0 authentication. Access user calendars, send emails, and interact with Chat spaces programmatically.

Overview

The Google integration provides:

  • Calendar Management: Create, read, update, and delete calendar events
  • Email Operations: Read, send, and manage Gmail messages and threads
  • Chat Integration: Send messages and interact with Google Chat spaces
  • OAuth 2.0 Authentication: Secure per-user authorization
  • Automatic Token Refresh: Seamless token management
  • Unified API: Single authentication flow for all Google services

Features

Google Calendar

  • List all calendars for a user
  • List events across all calendars or specific calendars
  • Create, update, and delete events
  • Manage attendees and invitations
  • Support for recurring events
  • Time zone handling

Gmail

  • List email threads with metadata
  • Get full thread conversations
  • List and search individual messages
  • Send emails with CC and BCC
  • Manage labels and categories
  • Trash and archive messages

Google Chat

  • List spaces (rooms and DMs)
  • Send and update messages
  • Read message history
  • Manage space members
  • Thread support for conversations

Prerequisites

1. Google Cloud Project

Create a Google Cloud project and enable APIs:

  1. Go to Google Cloud Console
  2. Create a new project or select existing
  3. Enable the following APIs:
    • Google Calendar API
    • Gmail API
    • Google Chat API

2. OAuth 2.0 Credentials

Create OAuth 2.0 credentials:

  1. Go to APIs & ServicesCredentials

  2. Click Create CredentialsOAuth 2.0 Client ID

  3. Choose Web application

  4. Add authorized redirect URI:

    http://localhost:4002/oauth/google/callback

    For production, use your deployed URL.

  5. Save Client ID and Client Secret

3. OAuth Scopes

The integration requires these scopes:

  • https://www.googleapis.com/auth/calendar - Calendar access
  • https://www.googleapis.com/auth/gmail.modify - Gmail read/write
  • https://www.googleapis.com/auth/chat.spaces - Chat spaces access
  • https://www.googleapis.com/auth/chat.messages - Send/read messages

These are automatically requested during authorization.

Configuration

Environment Variables

Add to your .env file:

# Google OAuth Configuration
GOOGLE_CLIENT_ID=your-client-id.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=your-client-secret
GOOGLE_REDIRECT_URI=http://localhost:4002/oauth/google/callback

# Optional: Token storage (default: redis)
MOCK_AUTH_STORAGE=redis

Docker Compose

Update docker-compose.yml:

services:
api:
environment:
- GOOGLE_CLIENT_ID=${GOOGLE_CLIENT_ID}
- GOOGLE_CLIENT_SECRET=${GOOGLE_CLIENT_SECRET}
- GOOGLE_REDIRECT_URI=http://localhost:4002/oauth/google/callback
- MOCK_AUTH_STORAGE=redis

Setup

1. Install Dependencies

The required packages are already in requirements.txt:

google-auth==2.27.0
google-auth-oauthlib==1.2.0
google-api-python-client==2.115.0

2. Start Services

make dev

3. Verify Configuration

Check that environment variables are set:

curl http://localhost:3007/health

Usage

Step 1: Generate JWT Token

Create a JWT token with user email:

curl -X POST http://localhost:3007/admin/token \
-H "Content-Type: application/json" \
-H "X-API-KEY: your-api-key" \
-d '{
"tenant_id": "acme",
"user_email": "user@example.com",
"user_display_name": "John Doe",
"connections": {
"google": {}
}
}'

Response:

{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

Step 2: Check Authorization Status

Check if the user has authorized Google access:

curl -H "X-JWT-Token: YOUR_TOKEN" \
http://localhost:3007/oauth/google/status

Response (not authorized):

{
"status": "needs_oauth",
"user_email": "user@example.com",
"message": "User needs to authorize Google access",
"auth_url": "http://localhost:3007/oauth/google/authorize?tenant_id=acme&user_email=user@example.com"
}

Step 3: Complete OAuth Flow

Open the auth_url in a browser. The user will:

  1. See Google's authorization page
  2. Grant access to Calendar, Gmail, and Chat
  3. Get redirected to a success page
  4. See their authorization is complete

The OAuth flow:

  • Uses JWT-encoded state tokens for CSRF protection
  • Verifies the authenticated email matches the JWT token email
  • Stores access and refresh tokens securely in Redis
  • Shows a beautiful success page with automatic close attempt

Step 4: Use Google Services

Calendar

List all events:

curl -H "X-JWT-Token: YOUR_TOKEN" \
"http://localhost:3007/google/calendar/events?time_min=2026-01-12T00:00:00Z"

Create an event:

curl -X POST http://localhost:3007/google/calendar/calendars/primary/events \
-H "X-JWT-Token: YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"summary": "Team Meeting",
"start_datetime": "2026-01-15T10:00:00",
"start_timezone": "America/Los_Angeles",
"end_datetime": "2026-01-15T11:00:00",
"end_timezone": "America/Los_Angeles",
"description": "Weekly team sync",
"attendee_emails": ["alice@example.com"]
}'

Gmail

List threads:

curl -H "X-JWT-Token: YOUR_TOKEN" \
"http://localhost:3007/google/gmail/threads?query=is:unread&max_results=50"

Send email:

curl -X POST http://localhost:3007/google/gmail/messages/send \
-H "X-JWT-Token: YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"to": "alice@example.com",
"subject": "Hello from API",
"body": "This email was sent via the Constellation API"
}'

Chat

List spaces:

curl -H "X-JWT-Token: YOUR_TOKEN" \
http://localhost:3007/google/chat/spaces

Send message:

curl -X POST http://localhost:3007/google/chat/spaces/SPACE_ID/messages \
-H "X-JWT-Token: YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"text": "Hello team! This is from the API."
}'

Authentication Details

OAuth Flow

The OAuth authorization flow:

  1. Initiate: User visits /oauth/google/authorize with tenant_id and user_email
  2. State Token: API creates JWT state token encoding tenant_id, user_email, and timestamp
  3. Redirect: User redirected to Google with combined scopes and state token
  4. Authorization: User grants access on Google's page
  5. Callback: Google redirects to /oauth/google/callback with code and state
  6. Verification: API verifies state token and exchanges code for tokens
  7. Email Check: API verifies OAuth email matches JWT token email
  8. Storage: Tokens stored in Redis with expiration
  9. Success: User sees success page

Token Management

Storage Structure:

Redis Key: auth_tokens:{tenant_id}:{user_email}:google
Value: {
"access_token": "ya29.a0...",
"refresh_token": "1//0e...",
"expires_at": "2026-01-12T11:00:00Z",
"scopes": ["calendar", "gmail", "chat"]
}

Automatic Refresh:

  • Access tokens expire after 1 hour
  • API automatically refreshes tokens on 401 errors
  • Refresh tokens are long-lived (until revoked)
  • Users only need to authorize once

Token Revocation:

curl -X DELETE http://localhost:3007/oauth/google/revoke \
-H "X-JWT-Token: YOUR_TOKEN"

Security

  • CSRF Protection: JWT-encoded state tokens prevent CSRF attacks
  • Email Verification: Ensures OAuth user matches JWT token user
  • Secure Storage: Tokens stored in Redis with encryption at rest
  • Scope Limitation: Only requests necessary scopes
  • HTTPS Required: Production deployments must use HTTPS

Error Handling

OAuth Required

When tokens are missing or expired:

Request:

curl -H "X-JWT-Token: YOUR_TOKEN" \
http://localhost:3007/google/calendar/events

Response (401):

{
"detail": {
"action": "oauth_required",
"message": "User needs to authorize Google access",
"auth_url": "http://localhost:3007/oauth/google/authorize?tenant_id=acme&user_email=user@example.com"
}
}

Solution: Direct user to auth_url to complete OAuth.

Email Mismatch

When OAuth email doesn't match JWT:

Response (403):

{
"detail": "Email mismatch: You authenticated with alice@gmail.com but the authorization was requested for bob@example.com. Please use the correct Google account."
}

Solution: User must authorize with the correct Google account.

API Errors

Google API errors are passed through:

Response (varies):

{
"detail": "Google Calendar API error: {\"error\": {\"code\": 404, \"message\": \"Not Found\"}}"
}

Solution: Check error message for specific issue.

Rate Limits

Google APIs have the following rate limits:

ServiceLimit
Calendar API1,000,000 queries/day
Gmail API250 quota units/second/user
Chat API60 requests/minute/user

The API handles rate limits with:

  • Automatic exponential backoff
  • Retry logic with jitter
  • Request queuing for high-volume operations

Best Practices

1. Token Management

  • Check authorization status before making requests
  • Handle oauth_required responses by redirecting users
  • Don't store tokens in your application (use the API's storage)
  • Revoke tokens when users disconnect

2. Error Handling

  • Always handle 401 errors with OAuth redirect
  • Implement retry logic for transient errors
  • Log errors for debugging
  • Show user-friendly error messages

3. Performance

  • Use the /google/calendar/events endpoint to get all events at once
  • Use Gmail threads instead of individual messages for conversations
  • Implement pagination for large result sets
  • Cache frequently accessed data

4. Security

  • Always use HTTPS in production
  • Validate user_email matches authenticated user
  • Implement proper CORS policies
  • Rotate API keys regularly
  • Monitor for suspicious activity

Troubleshooting

OAuth Redirect URI Mismatch

Error: "redirect_uri_mismatch"

Solution:

  1. Check GOOGLE_REDIRECT_URI matches Google Console
  2. Add redirect URI to authorized list in Google Console
  3. Ensure URL includes protocol (http:// or https://)

Token Refresh Failed

Error: "Token refresh failed. User needs to re-authorize."

Solution:

  • User must revoke and re-authorize
  • Visit /oauth/google/revoke then /oauth/google/authorize

Email Verification Failed

Error: "Email mismatch"

Solution:

  • User authenticated with wrong Google account
  • Generate new JWT token with correct email
  • Re-authorize with correct account

API Not Enabled

Error: "Google Calendar API has not been used in project..."

Solution:

  1. Go to Google Cloud Console
  2. Enable Calendar/Gmail/Chat APIs
  3. Wait a few minutes for propagation

Examples

Complete Workflow Example

import requests

BASE_URL = "http://localhost:3007"
API_KEY = "your-api-key"

# 1. Generate JWT token
response = requests.post(
f"{BASE_URL}/admin/token",
headers={"X-API-KEY": API_KEY},
json={
"tenant_id": "acme",
"user_email": "user@example.com",
"user_display_name": "John Doe",
"connections": {"google": {}}
}
)
token = response.json()["token"]

# 2. Check authorization status
response = requests.get(
f"{BASE_URL}/oauth/google/status",
headers={"X-JWT-Token": token}
)
status = response.json()

if status["status"] == "needs_oauth":
print(f"Please authorize: {status['auth_url']}")
input("Press Enter after authorization...")

# 3. List calendar events
response = requests.get(
f"{BASE_URL}/google/calendar/events",
headers={"X-JWT-Token": token},
params={"time_min": "2026-01-12T00:00:00Z"}
)
events = response.json()["data"]
print(f"Found {len(events)} events")

# 4. Send email
response = requests.post(
f"{BASE_URL}/google/gmail/messages/send",
headers={"X-JWT-Token": token},
json={
"to": "alice@example.com",
"subject": "Test Email",
"body": "This is a test email"
}
)
print(f"Email sent: {response.json()}")

API Reference

For complete API documentation, see:

Support

For issues or questions:

  • Check the logs: docker-compose logs api
  • Review Google Cloud Console for API status
  • Verify OAuth credentials are correct
  • Ensure all required scopes are enabled