Dashboard-Automatizase/docs/google-calendar-callback-interception.md
Luis Erlacher 0152a2fda0 feat: add n8n API testing script for Google OAuth2 schema and existing credentials
- Implemented a bash script to test n8n API and retrieve credential schemas.
- Added types for API responses, Google Calendar, and WhatsApp instances.
- Configured Vitest for testing with React and added setup for testing-library.
2025-10-10 14:29:02 -03:00

7.2 KiB

Interceptação de Callback OAuth Google Calendar

Visão Geral

Este documento explica como o dashboard intercepta o callback do Google OAuth antes de enviar para o n8n, permitindo salvar o status da integração no banco de dados.

Fluxo Completo

1. Usuário clica em "Conectar Google Calendar" no dashboard
   ↓
2. Dashboard gera oauth_url do Google diretamente:
   - client_id = NEXT_PUBLIC_GOOGLE_CLIENT_ID
   - redirect_uri = http://localhost:3000/api/google-calendar/callback
   - state = user_id
   - scope = https://www.googleapis.com/auth/calendar
   - access_type = offline
   - prompt = consent
   ↓
3. Dashboard redireciona usuário para oauth_url do Google
   ↓
4. Usuário autoriza no Google
   ↓
5. Google redireciona para: http://localhost:3000/api/google-calendar/callback?code=...&state=...&scope=...
   ↓
6. Dashboard intercepta callback:
   - Salva status "connecting" na tabela portal.integrations (usando state = user_id)
   - Redireciona para: https://n8n.automatizase.com.br/rest/oauth2-credential/callback?code=...&state=...&scope=...
   ↓
7. n8n processa callback normalmente:
   - Troca code por access_token e refresh_token
   - Salva na credencial OAuth2
   - Redireciona de volta para dashboard
   ↓
8. Dashboard detecta sucesso e mostra toast "Conectado com sucesso"

Componentes

1. Dashboard (/app/dashboard/page.tsx)

Gera a oauth_url do Google diretamente no frontend:

const handleConnectGoogleCalendar = async () => {
  const oauthUrl = new URL("https://accounts.google.com/o/oauth2/v2/auth");
  oauthUrl.searchParams.set("client_id", NEXT_PUBLIC_GOOGLE_CLIENT_ID);
  oauthUrl.searchParams.set("redirect_uri", `${origin}/api/google-calendar/callback`);
  oauthUrl.searchParams.set("state", user.id);
  oauthUrl.searchParams.set("scope", "https://www.googleapis.com/auth/calendar");
  oauthUrl.searchParams.set("access_type", "offline");
  oauthUrl.searchParams.set("prompt", "consent");

  window.location.href = oauthUrl.toString();
};

2. Endpoint de Callback (/app/api/google-calendar/callback/route.ts)

Este endpoint intercepta o callback do Google:

// Recebe: ?code=...&state=...&scope=...
// 1. Salva no Supabase (portal.integrations) usando state = user_id
// 2. Redireciona para n8n com mesmos parâmetros

Responsabilidades:

  • Receber callback do Google com parâmetros OAuth
  • Extrair user_id do state
  • Salvar status "connecting" no Supabase
  • Repassar TODOS os parâmetros para o n8n
  • Tratar erros do Google (error, error_description)

3. Credencial OAuth2 no n8n

A credencial no n8n deve estar configurada com:

  • Client ID: do Google Cloud Console
  • Client Secret: do Google Cloud Console
  • Authorization URL: https://accounts.google.com/o/oauth2/v2/auth
  • Access Token URL: https://oauth2.googleapis.com/token
  • Scope: https://www.googleapis.com/auth/calendar
  • Auth URI Query Parameters: access_type=offline&prompt=consent (para obter refresh_token)

Configuração

1. Google Cloud Console

Adicione as seguintes URLs aos Authorized redirect URIs:

Desenvolvimento:

http://localhost:3000/api/google-calendar/callback
https://n8n.automatizase.com.br/rest/oauth2-credential/callback

Produção:

https://dashboard.automatizase.com.br/api/google-calendar/callback
https://n8n.automatizase.com.br/rest/oauth2-credential/callback

Importante: Ambas URLs são necessárias porque:

  • A primeira intercepta o callback do Google
  • A segunda é para onde o dashboard redireciona (n8n processa)

2. Variáveis de Ambiente (.env.local)

Desenvolvimento (localhost):

# Google OAuth (mesmo Client ID do n8n)
NEXT_PUBLIC_GOOGLE_CLIENT_ID=your-client-id.apps.googleusercontent.com

# URL base do n8n (sem trailing slash)
N8N_BASE_URL=https://n8n.automatizase.com.br

# URL do site (localhost em dev)
NEXT_PUBLIC_SITE_URL=http://localhost:3000

Produção:

# Google OAuth (mesmo Client ID do n8n)
NEXT_PUBLIC_GOOGLE_CLIENT_ID=your-client-id.apps.googleusercontent.com

# URL base do n8n (sem trailing slash)
N8N_BASE_URL=https://n8n.automatizase.com.br

# URL do site (domínio em produção)
NEXT_PUBLIC_SITE_URL=https://dashboard.automatizase.com.br

IMPORTANTE: Use o mesmo Client ID que está configurado na credencial OAuth2 do n8n. Isso garante que os tokens gerados sejam compatíveis.

Tabela Supabase

-- portal.integrations
CREATE TABLE IF NOT EXISTS portal.integrations (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
  provider VARCHAR(50) NOT NULL, -- 'google_calendar'
  status VARCHAR(20) NOT NULL, -- 'connecting', 'connected', 'error'
  connected_at TIMESTAMPTZ,
  updated_at TIMESTAMPTZ DEFAULT NOW(),
  metadata JSONB,
  UNIQUE(user_id, provider)
);

Tratamento de Erros

Erro no Google OAuth

Google redireciona: /api/google-calendar/callback?error=access_denied
Dashboard redireciona: /dashboard?oauth_error=access_denied
Dashboard mostra toast: "Erro ao conectar Google Calendar"

Erro ao Salvar no Supabase

  • Log do erro no console
  • Não bloqueia o fluxo (continua redirecionando para n8n)
  • Permite que OAuth funcione mesmo com falha no banco

Erro no n8n

n8n redireciona: /dashboard?oauth_error=...
Dashboard mostra toast: "Erro ao conectar Google Calendar"

Segurança

  1. State Parameter: O n8n deve gerar state único e validar no callback
  2. HTTPS Only: Todos os endpoints devem usar HTTPS em produção
  3. CORS: Configurar CORS no n8n se necessário
  4. Validação: Validar todos os parâmetros antes de redirecionar

Logs e Debug

// Endpoint de callback loga:
console.log("Redirecionando para n8n:", n8nCallbackUrl.toString());
console.error("Erro ao salvar no Supabase:", dbError);
console.error("Erro no OAuth do Google:", error);

Diferenças do Fluxo Anterior

Fluxo Anterior (Tentativa 1 - Não Funciona)

  • Dashboard trocava code por tokens diretamente
  • Dashboard tentava salvar credencial via API REST do n8n
  • BUG: n8n API REST valida schema OAuth2 de forma incorreta

Fluxo Anterior (Tentativa 2 - Complexo)

  • Dashboard chamava webhook n8n para gerar oauth_url
  • n8n retornava oauth_url
  • Dashboard redirecionava para Google
  • PROBLEMA: Overhead desnecessário, n8n não precisa gerar URL

Fluxo Atual (Funciona e é Simples)

  • Dashboard gera oauth_url do Google diretamente (sem chamar n8n)
  • Dashboard apenas intercepta callback e salva no banco
  • Dashboard redireciona para n8n processar OAuth
  • n8n faz toda a troca de tokens e salva na credencial
  • VANTAGEM: Simples, rápido, sem overhead, usa OAuth nativo do n8n

Vantagens

  1. Usa sistema OAuth2 nativo do n8n (sem bugs)
  2. Permite salvar status no banco antes de processar
  3. Mantém controle sobre experiência do usuário
  4. n8n gerencia tokens automaticamente (refresh, revoke)
  5. Simples de manter (apenas redirect, sem lógica complexa)

Próximos Passos

Após OAuth conectado, você pode:

  1. Atualizar status para "connected" quando n8n confirmar
  2. Adicionar webhook do n8n para notificar quando eventos de calendário ocorrem
  3. Exibir calendários e eventos no dashboard
  4. Permitir desconexão (revoke do OAuth)