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.
This commit is contained in:
@@ -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() {
|
||||
<div className="space-y-2">
|
||||
<Label className="flex items-center gap-2">
|
||||
<Key className="w-4 h-4" />
|
||||
Google Service Account JSON
|
||||
Google OAuth Config
|
||||
</Label>
|
||||
<Textarea
|
||||
value={settings.google_service_account_json || ''}
|
||||
onChange={(e) => setSettings({ ...settings, google_service_account_json: e.target.value })}
|
||||
placeholder='{"type": "service_account", "project_id": "...", "private_key": "...", "client_email": "..."}'
|
||||
value={settings.google_oauth_config || ''}
|
||||
onChange={(e) => setSettings({ ...settings, google_oauth_config: e.target.value })}
|
||||
placeholder='{"client_id": "...", "client_secret": "...", "refresh_token": "..."}'
|
||||
className="min-h-[120px] font-mono text-sm border-2"
|
||||
/>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Paste entire service account JSON from Google Cloud Console. Calendar must be shared with the service account email.
|
||||
</p>
|
||||
{settings.google_service_account_json && (
|
||||
<div className="space-y-1">
|
||||
<p className="text-sm text-muted-foreground">
|
||||
OAuth2 credentials untuk personal Gmail account. Gunakan <a href="/get-google-refresh-token.html" target="_blank" className="text-blue-600 underline">tool ini</a> untuk generate refresh token.
|
||||
</p>
|
||||
</div>
|
||||
{settings.google_oauth_config && (
|
||||
<Alert>
|
||||
<AlertTriangle className="w-4 h-4" />
|
||||
<AlertDescription>
|
||||
Service account configured. Calendar ID: {settings.integration_google_calendar_id || 'Not set'}
|
||||
OAuth configured. Calendar ID: {settings.integration_google_calendar_id || 'Not set'}
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
)}
|
||||
@@ -373,8 +375,8 @@ export function IntegrasiTab() {
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={async () => {
|
||||
if (!settings.integration_google_calendar_id || !settings.google_service_account_json) {
|
||||
toast({ title: "Error", description: "Lengkapi Calendar ID dan Service Account JSON", variant: "destructive" });
|
||||
if (!settings.integration_google_calendar_id || !settings.google_oauth_config) {
|
||||
toast({ title: "Error", description: "Lengkapi Calendar ID dan OAuth Config", variant: "destructive" });
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user