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

223 lines
7.2 KiB
Markdown

# 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:
```typescript
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:
```typescript
// 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):**
```bash
# 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:**
```bash
# 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
```sql
-- 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
```typescript
// 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)