# Webhook n8n para Google Calendar OAuth ## Visão Geral O portal enviará uma requisição webhook ao n8n quando o usuário clicar em "Conectar Google Calendar". O n8n será responsável por: 1. Receber o webhook com os dados do usuário 2. Iniciar o fluxo OAuth do Google Calendar 3. Armazenar as credenciais OAuth no n8n 4. Salvar o status da integração no Supabase 5. Notificar o portal sobre o sucesso/erro --- ## Fluxo de Integração ``` Portal Dashboard │ ├─> Usuário clica "Conectar Google Calendar" │ ├─> Portal envia POST para webhook n8n │ Payload: { user_id, user_email, redirect_uri } │ └─> n8n recebe webhook │ ├─> n8n inicia OAuth Google Calendar │ - redirect_uri aponta para n8n │ - Usuário autoriza no Google │ ├─> n8n recebe callback OAuth do Google │ - Salva credenciais no n8n credentials store │ ├─> n8n salva status no Supabase │ UPDATE portal.integrations │ SET status = 'connected', connected_email = :email │ WHERE user_id = :user_id AND provider = 'google_calendar' │ └─> n8n redireciona usuário de volta ao portal - URL: {portal_redirect_uri}?oauth_success=true - Em caso de erro: {portal_redirect_uri}?oauth_error={message} ``` --- ## Endpoint do Webhook n8n ### URL ``` POST https://n8n.automatizase.com.br/webhook/google-calendar-sync ``` ### Request Headers ``` Content-Type: application/json ``` ### Request Body ```json { "user_id": "uuid-do-usuario-supabase", "user_email": "usuario@exemplo.com", "redirect_uri": "https://portal.automatizase.com.br/dashboard" } ``` ### Response (Imediata) ```json { "status": "processing", "message": "OAuth flow iniciado. Você será redirecionado em instantes.", "oauth_url": "https://accounts.google.com/o/oauth2/v2/auth?..." } ``` O n8n deve redirecionar o usuário para `oauth_url` imediatamente após receber a requisição. --- ## Configuração OAuth no Google Cloud Console ### Criar Credenciais OAuth 2.0 1. Acesse [Google Cloud Console](https://console.cloud.google.com/) 2. Crie um novo projeto ou selecione um existente 3. Navegue para **APIs & Services > Credentials** 4. Clique em **Create Credentials > OAuth 2.0 Client ID** 5. Configure: - **Application type:** Web application - **Name:** AutomatizaSE Portal - Google Calendar - **Authorized redirect URIs:** ``` https://n8n.automatizase.com.br/webhook/google-calendar-oauth-callback ``` 6. Anote o **Client ID** e **Client Secret** ### Escopos Necessários ``` https://www.googleapis.com/auth/calendar.readonly https://www.googleapis.com/auth/calendar.events ``` --- ## Implementação no n8n ### Workflow n8n #### 1. Webhook Node (Trigger) - **Webhook Path:** `/google-calendar-sync` - **Method:** POST - **Authentication:** None (ou Basic Auth se quiser proteger) - **Response Mode:** Immediately - **Response Data:** JSON #### 2. Set Node (Preparar OAuth URL) ```json { "user_id": "{{$json.body.user_id}}", "user_email": "{{$json.body.user_email}}", "redirect_uri": "{{$json.body.redirect_uri}}", "oauth_url": "https://accounts.google.com/o/oauth2/v2/auth?client_id={{$env.GOOGLE_CLIENT_ID}}&redirect_uri=https://n8n.automatizase.com.br/webhook/google-calendar-oauth-callback&response_type=code&scope=https://www.googleapis.com/auth/calendar.readonly https://www.googleapis.com/auth/calendar.events&access_type=offline&state={{$json.body.user_id}}" } ``` #### 3. Respond to Webhook Node ```json { "status": "processing", "oauth_url": "{{$json.oauth_url}}" } ``` #### 4. HTTP Redirect (Redirecionar para Google OAuth) - Use um nó HTTP Request ou Respond to Webhook com `redirect` para enviar o usuário para o Google #### 5. Webhook Node (OAuth Callback) - **Webhook Path:** `/google-calendar-oauth-callback` - **Method:** GET - **Authentication:** None - Recebe: - `code` (authorization code do Google) - `state` (user_id) #### 6. HTTP Request (Trocar Code por Token) ``` POST https://oauth2.googleapis.com/token Body: { "code": "{{$json.query.code}}", "client_id": "{{$env.GOOGLE_CLIENT_ID}}", "client_secret": "{{$env.GOOGLE_CLIENT_SECRET}}", "redirect_uri": "https://n8n.automatizase.com.br/webhook/google-calendar-oauth-callback", "grant_type": "authorization_code" } ``` Response: ```json { "access_token": "ya29.xxx", "refresh_token": "1//xxx", "expires_in": 3599, "token_type": "Bearer" } ``` #### 7. HTTP Request (Obter Email do Usuário Google) ``` GET https://www.googleapis.com/oauth2/v1/userinfo?access_token={{$json.access_token}} ``` Response: ```json { "email": "usuario@gmail.com", "verified_email": true } ``` #### 8. Save Credentials to n8n Store - Use o nó **n8n Credentials** para salvar o `access_token` e `refresh_token` - Associar ao `user_id` vindo do `state` #### 9. Supabase Node (Update Integration Status) ```sql INSERT INTO portal.integrations (user_id, provider, status, connected_email, connected_at, updated_at) VALUES (:user_id, 'google_calendar', 'connected', :google_email, NOW(), NOW()) ON CONFLICT (user_id, provider) DO UPDATE SET status = 'connected', connected_email = :google_email, connected_at = NOW(), updated_at = NOW(); ``` Parâmetros: - `:user_id` = `{{$json.query.state}}` (user_id vindo do state) - `:google_email` = `{{$json.email}}` (email do Google) #### 10. HTTP Redirect (Voltar ao Portal) ``` Redirect to: {{$node["Webhook"].json.body.redirect_uri}}?oauth_success=true ``` Em caso de erro: ``` Redirect to: {{$node["Webhook"].json.body.redirect_uri}}?oauth_error={{$json.error_message}} ``` --- ## Variáveis de Ambiente no n8n ```bash GOOGLE_CLIENT_ID=xxxxx.apps.googleusercontent.com GOOGLE_CLIENT_SECRET=GOCSPX-xxxxx SUPABASE_URL=https://xxxxx.supabase.co SUPABASE_SERVICE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.xxxxx ``` --- ## Tratamento de Erros ### Cenários de Erro | Erro | Causa | Ação do n8n | |------|-------|-------------| | User cancela OAuth | Usuário clica "Cancelar" no Google | Redirecionar com `oauth_error=user_cancelled` | | Token inválido | Google rejeita o code | Redirecionar com `oauth_error=invalid_token` | | Supabase falha | Erro ao salvar status | Redirecionar com `oauth_error=database_error` | | Credenciais inválidas | Client ID/Secret errados | Redirecionar com `oauth_error=config_error` | ### Response de Erro ```json { "status": "error", "error_message": "Descrição do erro" } ``` --- ## Segurança ### Validações Necessárias 1. **Validar user_id:** Verificar se é um UUID válido 2. **Validar redirect_uri:** Whitelist de domínios permitidos ```javascript const allowedDomains = [ 'https://portal.automatizase.com.br', 'http://localhost:3000' // apenas dev ] ``` 3. **State Parameter:** Usar `user_id` como state para evitar CSRF 4. **HTTPS Only:** Todas as URLs devem usar HTTPS em produção --- ## Testes ### Teste Manual 1. **Testar Webhook:** ```bash curl -X POST https://n8n.automatizase.com.br/webhook/google-calendar-sync \ -H "Content-Type: application/json" \ -d '{ "user_id": "123e4567-e89b-12d3-a456-426614174000", "user_email": "teste@exemplo.com", "redirect_uri": "http://localhost:3000/dashboard" }' ``` 2. **Verificar Redirect:** Deve retornar uma URL OAuth do Google 3. **Completar OAuth:** Clicar no link e autorizar 4. **Verificar Supabase:** ```sql SELECT * FROM portal.integrations WHERE user_id = '123e4567-e89b-12d3-a456-426614174000'; ``` 5. **Verificar Redirect:** Deve voltar ao portal com `?oauth_success=true` --- ## Exemplo de Implementação Simplificada no Portal ### Component: GoogleCalendarCard.tsx ```typescript const handleConnectGoogleCalendar = async () => { try { setLoading(true) const { data: { user } } = await supabase.auth.getUser() if (!user) throw new Error('User not authenticated') // Enviar webhook ao n8n const response = await fetch(process.env.NEXT_PUBLIC_N8N_WEBHOOK_GOOGLE_CALENDAR!, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ user_id: user.id, user_email: user.email, redirect_uri: `${window.location.origin}/dashboard` }) }) const data = await response.json() if (data.oauth_url) { // Redirecionar para OAuth do Google window.location.href = data.oauth_url } else { throw new Error('Failed to initiate OAuth flow') } } catch (error) { console.error('Error connecting Google Calendar:', error) setToastMessage('Erro ao conectar Google Calendar') setToastType('error') setToastVisible(true) } finally { setLoading(false) } } ``` ### Environment Variable ```bash NEXT_PUBLIC_N8N_WEBHOOK_GOOGLE_CALENDAR=https://n8n.automatizase.com.br/webhook/google-calendar-sync ``` --- ## Checklist de Implementação ### n8n - [ ] Criar workflow no n8n - [ ] Configurar webhook `/google-calendar-sync` - [ ] Configurar webhook `/google-calendar-oauth-callback` - [ ] Obter Google OAuth Client ID e Secret - [ ] Configurar variáveis de ambiente no n8n - [ ] Adicionar redirect URI no Google Cloud Console - [ ] Implementar lógica de troca de code por token - [ ] Implementar salvamento no Supabase - [ ] Implementar redirect de volta ao portal - [ ] Testar fluxo completo ### Portal - [ ] Atualizar `GoogleCalendarCard` para usar webhook - [ ] Adicionar variável `NEXT_PUBLIC_N8N_WEBHOOK_GOOGLE_CALENDAR` - [ ] Remover lógica OAuth direta do portal - [ ] Manter lógica de callback para receber `?oauth_success=true` - [ ] Testar integração end-to-end --- ## Benefícios desta Abordagem 1. **Segurança:** Credenciais OAuth ficam apenas no n8n 2. **Centralização:** n8n gerencia todas as credenciais 3. **Manutenção:** Mais fácil atualizar lógica OAuth 4. **Reutilização:** Outros workflows n8n podem usar as mesmas credenciais 5. **Isolamento:** Portal não precisa lidar com complexidade do OAuth --- ## Referências - [Google Calendar API](https://developers.google.com/calendar/api/guides/overview) - [OAuth 2.0](https://developers.google.com/identity/protocols/oauth2) - [n8n Webhook Node](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.webhook/) - [n8n HTTP Request Node](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.httprequest/)