- 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.
10 KiB
10 KiB
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:
- Receber o webhook com os dados do usuário
- Iniciar o fluxo OAuth do Google Calendar
- Armazenar as credenciais OAuth no n8n
- Salvar o status da integração no Supabase
- 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
{
"user_id": "uuid-do-usuario-supabase",
"user_email": "usuario@exemplo.com",
"redirect_uri": "https://portal.automatizase.com.br/dashboard"
}
Response (Imediata)
{
"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
-
Acesse Google Cloud Console
-
Crie um novo projeto ou selecione um existente
-
Navegue para APIs & Services > Credentials
-
Clique em Create Credentials > OAuth 2.0 Client ID
-
Configure:
- Application type: Web application
- Name: AutomatizaSE Portal - Google Calendar
- Authorized redirect URIs:
https://n8n.automatizase.com.br/webhook/google-calendar-oauth-callback
-
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)
{
"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
{
"status": "processing",
"oauth_url": "{{$json.oauth_url}}"
}
4. HTTP Redirect (Redirecionar para Google OAuth)
- Use um nó HTTP Request ou Respond to Webhook com
redirectpara 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:
{
"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:
{
"email": "usuario@gmail.com",
"verified_email": true
}
8. Save Credentials to n8n Store
- Use o nó n8n Credentials para salvar o
access_tokenerefresh_token - Associar ao
user_idvindo dostate
9. Supabase Node (Update Integration Status)
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
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
{
"status": "error",
"error_message": "Descrição do erro"
}
Segurança
Validações Necessárias
- Validar user_id: Verificar se é um UUID válido
- Validar redirect_uri: Whitelist de domínios permitidos
const allowedDomains = [ 'https://portal.automatizase.com.br', 'http://localhost:3000' // apenas dev ] - State Parameter: Usar
user_idcomo state para evitar CSRF - HTTPS Only: Todas as URLs devem usar HTTPS em produção
Testes
Teste Manual
-
Testar Webhook:
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" }' -
Verificar Redirect: Deve retornar uma URL OAuth do Google
-
Completar OAuth: Clicar no link e autorizar
-
Verificar Supabase:
SELECT * FROM portal.integrations WHERE user_id = '123e4567-e89b-12d3-a456-426614174000'; -
Verificar Redirect: Deve voltar ao portal com
?oauth_success=true
Exemplo de Implementação Simplificada no Portal
Component: GoogleCalendarCard.tsx
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
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
GoogleCalendarCardpara 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
- Segurança: Credenciais OAuth ficam apenas no n8n
- Centralização: n8n gerencia todas as credenciais
- Manutenção: Mais fácil atualizar lógica OAuth
- Reutilização: Outros workflows n8n podem usar as mesmas credenciais
- Isolamento: Portal não precisa lidar com complexidade do OAuth