Dashboard-Automatizase/docs/n8n-webhook-oauth-url.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

5.1 KiB

Webhook n8n para Gerar OAuth URL

Problema

O endpoint REST /rest/oauth2-credential/auth do n8n requer cookies de sessão (usuário logado), não aceita API Key.

Solução

Criar um workflow no n8n com webhook que gera a oauth_url internamente.

Workflow n8n

1. Webhook (Trigger)

  • Path: /webhook/google-calendar-oauth-url
  • Method: GET ou POST
  • Authentication: None (webhook público)

2. Code Node (Gerar oauth_url)

// Configuração
const credentialId = "ccTThTS9TKsejR7W"; // Seu credential ID
const clientId = "174466774807-xxx.apps.googleusercontent.com"; // Google Client ID
const callbackUrl = $json.query?.callbackUrl || "http://localhost:3000/api/google-calendar/callback";

// Gerar CSRF token (aleatório)
const csrfToken = Math.random().toString(36).substring(2, 15) +
                  Math.random().toString(36).substring(2, 15);

// Criar state (formato do n8n)
const state = {
  token: csrfToken,
  cid: credentialId,
  createdAt: Date.now()
};

// Codificar state em base64
const stateBase64 = Buffer.from(JSON.stringify(state)).toString('base64');

// Construir oauth_url
const oauthUrl = new URL("https://accounts.google.com/o/oauth2/v2/auth");
oauthUrl.searchParams.set("client_id", clientId);
oauthUrl.searchParams.set("redirect_uri", callbackUrl);
oauthUrl.searchParams.set("response_type", "code");
oauthUrl.searchParams.set("scope", "https://www.googleapis.com/auth/calendar https://www.googleapis.com/auth/calendar.events");
oauthUrl.searchParams.set("access_type", "offline");
oauthUrl.searchParams.set("prompt", "consent");
oauthUrl.searchParams.set("state", stateBase64);

// Retornar
return {
  json: {
    oauthUrl: oauthUrl.toString(),
    state: stateBase64,
    credentialId: credentialId
  }
};

3. Respond to Webhook

Retorna o resultado:

{
  "oauthUrl": "https://accounts.google.com/o/oauth2/v2/auth?...",
  "state": "eyJ0b2tlbiI6InhjZDExMzkyLWUyMzkiLCJjaWQiOiJjY1RUaFRTOVRLc2VqUjdXIiwiY3JlYXRlZEF0IjoxNzU5OTUzNTY1MDI0fQ==",
  "credentialId": "ccTThTS9TKsejR7W"
}

Configuração no Dashboard

Atualize .env.local:

# Webhook do n8n para gerar oauth_url
N8N_OAUTH_URL_WEBHOOK=https://n8n.automatizase.com.br/webhook/google-calendar-oauth-url

Remova (não é mais necessário):

# N8N_API_KEY não é mais necessário

Atualizar API Route

app/api/google-calendar/auth/route.ts:

export async function GET(_request: NextRequest) {
  try {
    const webhookUrl = process.env.N8N_OAUTH_URL_WEBHOOK;
    const callbackUrl = `${process.env.NEXT_PUBLIC_SITE_URL}/api/google-calendar/callback`;

    if (!webhookUrl) {
      return NextResponse.json(
        { error: "N8N_OAUTH_URL_WEBHOOK not configured" },
        { status: 500 }
      );
    }

    // Chamar webhook do n8n
    const response = await fetch(
      `${webhookUrl}?callbackUrl=${encodeURIComponent(callbackUrl)}`
    );

    if (!response.ok) {
      const error = await response.text();
      console.error("n8n webhook error:", error);
      return NextResponse.json(
        { error: "Failed to generate OAuth URL" },
        { status: 500 }
      );
    }

    const data = await response.json();

    return NextResponse.json({
      oauthUrl: data.oauthUrl
    });
  } catch (error) {
    console.error("Error:", error);
    return NextResponse.json(
      { error: "Internal server error" },
      { status: 500 }
    );
  }
}

Validação do State no n8n

IMPORTANTE: O n8n vai validar o state quando receber o callback do Google. Como estamos gerando o state manualmente, precisamos desabilitar a validação CSRF ou salvar o token no n8n.

Opção 1: Desabilitar Validação (Mais Simples)

O n8n não valida CSRF token por padrão quando o callback vem pelo redirect do Google. Apenas valida o cid (credential ID).

Opção 2: Salvar Token (Mais Seguro)

Adicionar um nó no workflow que salva o csrfToken temporariamente (Redis, banco, etc) e validar no callback.

Fluxo Completo

1. Dashboard → GET /api/google-calendar/auth
   ↓
2. API Route → GET https://n8n.automatizase.com.br/webhook/google-calendar-oauth-url
   ↓
3. n8n Workflow gera state + oauth_url
   ↓
4. Dashboard redireciona para oauth_url
   ↓
5. Google → Callback http://localhost:3000/api/google-calendar/callback?code=...&state=...
   ↓
6. Dashboard salva no Supabase
   ↓
7. Dashboard → https://n8n.automatizase.com.br/rest/oauth2-credential/callback?code=...&state=...
   ↓
8. n8n processa OAuth e salva tokens
   ↓
9. Sucesso! ✅

Vantagens

Webhook público (sem autenticação) n8n controla geração do state Código simples e direto Fácil de debugar

Alternativa: State Simplificado

Se o n8n não validar o CSRF token, podemos usar um state mais simples:

const state = credentialId; // Apenas o credential ID

Teste primeiro para ver se o n8n aceita.

Teste

# Testar webhook
curl "https://n8n.automatizase.com.br/webhook/google-calendar-oauth-url?callbackUrl=http://localhost:3000/api/google-calendar/callback"

# Deve retornar:
# {"oauthUrl":"https://accounts.google.com/...","state":"...","credentialId":"..."}