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:
- Go to Google Cloud Console
- Create a new project or select existing
- Enable the following APIs:
- Google Calendar API
- Gmail API
- Google Chat API
2. OAuth 2.0 Credentials
Create OAuth 2.0 credentials:
-
Go to APIs & Services → Credentials
-
Click Create Credentials → OAuth 2.0 Client ID
-
Choose Web application
-
Add authorized redirect URI:
http://localhost:4002/oauth/google/callbackFor production, use your deployed URL.
-
Save Client ID and Client Secret
3. OAuth Scopes
The integration requires these scopes:
https://www.googleapis.com/auth/calendar- Calendar accesshttps://www.googleapis.com/auth/gmail.modify- Gmail read/writehttps://www.googleapis.com/auth/chat.spaces- Chat spaces accesshttps://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:
- See Google's authorization page
- Grant access to Calendar, Gmail, and Chat
- Get redirected to a success page
- 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:
- Initiate: User visits
/oauth/google/authorizewith tenant_id and user_email - State Token: API creates JWT state token encoding tenant_id, user_email, and timestamp
- Redirect: User redirected to Google with combined scopes and state token
- Authorization: User grants access on Google's page
- Callback: Google redirects to
/oauth/google/callbackwith code and state - Verification: API verifies state token and exchanges code for tokens
- Email Check: API verifies OAuth email matches JWT token email
- Storage: Tokens stored in Redis with expiration
- 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:
| Service | Limit |
|---|---|
| Calendar API | 1,000,000 queries/day |
| Gmail API | 250 quota units/second/user |
| Chat API | 60 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_requiredresponses 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/eventsendpoint 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:
- Check
GOOGLE_REDIRECT_URImatches Google Console - Add redirect URI to authorized list in Google Console
- 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/revokethen/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:
- Go to Google Cloud Console
- Enable Calendar/Gmail/Chat APIs
- 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