From 7d22a5328f1a53f76748416987c789aa0da4317f Mon Sep 17 00:00:00 2001 From: dwindown Date: Tue, 23 Dec 2025 14:06:42 +0700 Subject: [PATCH] Switch from Service Account to OAuth2 for Google Calendar (Personal Gmail) - Replace JWT service account authentication with OAuth2 refresh token flow - Service accounts cannot create Google Meet links for personal Gmail accounts - Update edge function to use OAuth2 token exchange - Change database column from google_service_account_json to google_oauth_config - Add helper tool (get-google-refresh-token.html) to generate OAuth credentials - Update IntegrasiTab UI to show OAuth config instead of service account - Add SQL migration file for new google_oauth_config column OAuth2 Config format: { "client_id": "...", "client_secret": "...", "refresh_token": "..." } This approach works with personal @gmail.com accounts without requiring Google Workspace or Domain-Wide Delegation. --- add-google-oauth-config.sql | 11 ++ get-google-refresh-token.html | 187 ++++++++++++++++++ .../admin/settings/IntegrasiTab.tsx | 36 ++-- .../create-google-meet-event/index.ts | 113 +++-------- 4 files changed, 239 insertions(+), 108 deletions(-) create mode 100644 add-google-oauth-config.sql create mode 100644 get-google-refresh-token.html diff --git a/add-google-oauth-config.sql b/add-google-oauth-config.sql new file mode 100644 index 0000000..736e4e7 --- /dev/null +++ b/add-google-oauth-config.sql @@ -0,0 +1,11 @@ +-- Add google_oauth_config column to platform_settings table +-- This replaces google_service_account_json for personal Gmail accounts + +ALTER TABLE platform_settings +ADD COLUMN IF NOT EXISTS google_oauth_config jsonb; + +-- Add comment +COMMENT ON COLUMN platform_settings.google_oauth_config IS 'OAuth2 configuration for Google Calendar API (for personal Gmail accounts). Format: {"client_id": "...", "client_secret": "...", "refresh_token": "..."}'; + +-- Note: The old google_service_account_json column can be dropped later if no longer needed +-- ALTER TABLE platform_settings DROP COLUMN IF EXISTS google_service_account_json; diff --git a/get-google-refresh-token.html b/get-google-refresh-token.html new file mode 100644 index 0000000..5bbb79a --- /dev/null +++ b/get-google-refresh-token.html @@ -0,0 +1,187 @@ + + + + + + Get Google OAuth Refresh Token + + + +
+

🔑 Generate Google OAuth Refresh Token

+ +
+

Step 1: Create Google Cloud Project

+
    +
  1. Go to Google Cloud Console
  2. +
  3. Create a new project or select existing one
  4. +
  5. Go to APIs & Services > Credentials
  6. +
  7. Click + Create CredentialsOAuth client ID
  8. +
  9. Application type: Web application
  10. +
  11. Add authorized redirect URI: https://developers.google.com/oauthplayground
  12. +
  13. Copy the Client ID and Client Secret
  14. +
+
+ +
+

Step 2: Configure OAuth Playground

+
    +
  1. Go to OAuth 2.0 Playground
  2. +
  3. Click the gear icon (⚙️) in the top right
  4. +
  5. Check Use your own OAuth credentials
  6. +
  7. Enter your Client ID and Client Secret from Step 1
  8. +
  9. Click Close
  10. +
+
+ +
+

Step 3: Get Refresh Token

+
    +
  1. In the left panel, select: +
      +
    • ☑️ Google Calendar API v3
    • +
    • Click Authorize APIs
    • +
    +
  2. +
  3. Sign in with your Google account and grant permissions
  4. +
  5. Click Exchange authorization code for tokens
  6. +
  7. Copy the Refresh Token from the right panel
  8. +
+
+ +
+

Step 4: Generate Configuration

+
+ + +
+
+ + +
+
+ + +
+ +
+ +
+
+ + + + diff --git a/src/components/admin/settings/IntegrasiTab.tsx b/src/components/admin/settings/IntegrasiTab.tsx index d086317..c4c0f96 100644 --- a/src/components/admin/settings/IntegrasiTab.tsx +++ b/src/components/admin/settings/IntegrasiTab.tsx @@ -17,7 +17,7 @@ interface IntegrationSettings { integration_whatsapp_number: string; integration_whatsapp_url: string; integration_google_calendar_id: string; - google_service_account_json?: string; + google_oauth_config?: string; integration_email_provider: string; integration_email_api_base_url: string; integration_privacy_url: string; @@ -76,7 +76,7 @@ export function IntegrasiTab() { integration_whatsapp_number: platformData.integration_whatsapp_number || '', integration_whatsapp_url: platformData.integration_whatsapp_url || '', integration_google_calendar_id: platformData.integration_google_calendar_id || '', - google_service_account_json: platformData.google_service_account_json || '', + google_oauth_config: platformData.google_oauth_config || '', integration_email_provider: platformData.integration_email_provider || 'mailketing', integration_email_api_base_url: platformData.integration_email_api_base_url || '', integration_privacy_url: platformData.integration_privacy_url || '/privacy', @@ -102,7 +102,7 @@ export function IntegrasiTab() { integration_whatsapp_number: settings.integration_whatsapp_number, integration_whatsapp_url: settings.integration_whatsapp_url, integration_google_calendar_id: settings.integration_google_calendar_id, - google_service_account_json: settings.google_service_account_json, + google_oauth_config: settings.google_oauth_config, integration_email_provider: settings.integration_email_provider, integration_email_api_base_url: settings.integration_email_api_base_url, integration_privacy_url: settings.integration_privacy_url, @@ -117,11 +117,11 @@ export function IntegrasiTab() { .eq('id', settings.id); if (platformError) { - // If schema cache error, try saving service account JSON separately via raw SQL - if (platformError.code === 'PGRST204' && settings.google_service_account_json) { + // If schema cache error, try saving OAuth config separately via raw SQL + if (platformError.code === 'PGRST204' && settings.google_oauth_config) { console.log('Schema cache error, using fallback RPC method'); const { error: rpcError } = await supabase.rpc('exec_sql', { - sql: `UPDATE platform_settings SET google_service_account_json = '${settings.google_service_account_json.replace(/'/g, "''")}'::jsonb WHERE id = '${settings.id}'` + sql: `UPDATE platform_settings SET google_oauth_config = '${settings.google_oauth_config.replace(/'/g, "''")}'::jsonb WHERE id = '${settings.id}'` }); if (rpcError) { @@ -349,22 +349,24 @@ export function IntegrasiTab() {