OAuth Web Dashboard Integration¶
This document describes the OAuth connection management endpoints for the web dashboard, allowing users to connect and disconnect Google Calendar and Gmail services.
Overview¶
The web dashboard provides a "Connected Services" page where users can: - View connection status for Google Calendar and Gmail - Connect new services via OAuth popup flow - Disconnect existing services with confirmation
Backend API Endpoints¶
All endpoints are in app/oauth/routes.py and require JWT authentication via Bearer token.
GET /auth/oauth/status¶
Returns the current OAuth connection status for the authenticated user.
Authentication: Required (JWT Bearer token)
Response:
{
"calendar": {
"connected": true,
"connected_at": "2025-01-10T08:30:00Z"
},
"gmail": {
"connected": false
}
}
Implementation Notes:
- Uses token_manager.has_valid_token() which handles auto-refresh of expired tokens
- Queries OAuthToken table for created_at metadata
- Tokens are considered connected if not expired and not revoked
GET /auth/oauth/connect-url¶
Returns an OAuth authorization URL that the frontend can open in a popup window.
Authentication: Required (JWT Bearer token)
Query Parameters:
- scope (required): One of calendar, gmail, or both
Response:
Implementation Notes:
- Generates a secure state token using secrets.token_urlsafe(32)
- Stores state with user_phone and source="web_dashboard"
- Frontend should open this URL in a popup window
DELETE /auth/oauth/revoke/{scope}¶
Revokes OAuth access for the specified service.
Authentication: Required (JWT Bearer token)
Path Parameters:
- scope: Must be calendar or gmail
Response:
Error Responses:
- 400: Invalid scope (not calendar or gmail)
- 404: Token not found
- 500: Failed to revoke access
Implementation Notes:
- Revokes token with Google via google_oauth.revoke_token()
- Soft-deletes token in database (sets revoked_at)
- Tracks disconnection event in Amplitude
Frontend Implementation¶
File Location¶
archety-web/app/dashboard/services/page.tsx
API Client Functions¶
Located in archety-web/lib/api.ts:
export const oauthApi = {
getStatus: async (): Promise<OAuthStatusResponse> => { ... },
getConnectUrl: async (scope: 'calendar' | 'gmail' | 'both'): Promise<OAuthConnectUrlResponse> => { ... },
revokeAccess: async (scope: 'calendar' | 'gmail'): Promise<{ status: string; scope: string }> => { ... },
}
OAuth Flow¶
- User clicks "Connect Google Calendar" or "Connect Gmail"
- Frontend calls
GET /auth/oauth/connect-url?scope=calendar - Frontend opens the returned URL in a popup window (600x700)
- User completes Google OAuth consent
- Google redirects to backend callback URL
- Backend stores token and closes popup (or redirects)
- Frontend polls for popup close every 500ms
- On popup close, frontend refreshes status via
GET /auth/oauth/status
Disconnect Flow¶
- User clicks "Disconnect" button
- Confirmation dialog appears
- User confirms disconnection
- Frontend calls
DELETE /auth/oauth/revoke/calendar - Frontend refreshes status
- Success message displayed
UI Components¶
ServiceCard¶
A reusable card component displaying: - Service icon and name - Connection status badge - Connected date (if connected) - "What Archety can access" list - Connect/Disconnect buttons - Confirmation dialog for disconnection
Access Descriptions¶
Google Calendar: - Read-only access to your calendar events - View event titles, times, and locations - Check for scheduling conflicts - Cannot create, edit, or delete events
Gmail: - Read-only access to recent emails - Identify urgent messages and deadlines - Scan for important sender patterns - Cannot send, delete, or modify emails
Database Schema¶
Uses existing OAuthToken model from app/models/database.py:
class OAuthToken(Base):
__tablename__ = "oauth_tokens"
id = Column(UUID)
user_id = Column(UUID, ForeignKey("users.id"))
scope = Column(String(50)) # 'calendar' or 'gmail'
access_token = Column(Text) # Encrypted
refresh_token = Column(Text) # Encrypted
expires_at = Column(DateTime)
revoked_at = Column(DateTime) # Soft delete
created_at = Column(DateTime)
Security Considerations¶
- JWT Authentication: All endpoints require valid JWT token
- State Token: OAuth flow uses secure random state to prevent CSRF
- Token Encryption: Access/refresh tokens encrypted with Fernet
- Soft Delete: Tokens are soft-deleted (revoked_at set) rather than hard deleted
- Google Revocation: Tokens are revoked with Google before database update
Testing¶
Via MCP Tools¶
Via Dashboard¶
- Navigate to
/dashboard/services - Connect/disconnect services
- Verify status updates correctly
Related Files¶
Backend:
- app/oauth/routes.py - API endpoints
- app/oauth/token_manager.py - Token storage/retrieval
- app/oauth/google_client.py - Google OAuth client
- app/dependencies.py - get_current_user dependency
Frontend:
- archety-web/app/dashboard/services/page.tsx - Services page
- archety-web/lib/api.ts - oauthApi functions
- archety-web/components/dashboard/DashboardNav.tsx - Navigation (includes Services link)