- 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.
133 lines
3.2 KiB
Markdown
133 lines
3.2 KiB
Markdown
# Erro: Invalid state format
|
|
|
|
> **⚠️ ATUALIZAÇÃO:** Este erro foi resolvido com uma nova abordagem. Veja [fluxo-final-google-oauth.md](./fluxo-final-google-oauth.md) para a solução final.
|
|
|
|
---
|
|
|
|
## O Problema
|
|
|
|
Quando tentamos conectar Google Calendar, o n8n retornou:
|
|
|
|
```html
|
|
<h4>Error: Invalid state format</h4>
|
|
```
|
|
|
|
## Causa Raiz
|
|
|
|
O dashboard estava enviando `user_id` no parâmetro `state`:
|
|
|
|
```typescript
|
|
const state = user.id; // ❌ ERRADO - UUID do user
|
|
```
|
|
|
|
Mas o **n8n espera receber o `credential_id`** no state:
|
|
|
|
```typescript
|
|
const state = n8nCredentialId; // ✅ CORRETO - ID da credencial n8n
|
|
```
|
|
|
|
## Por que isso acontece?
|
|
|
|
O n8n usa o `state` para identificar **qual credencial** deve ser atualizada com os tokens OAuth.
|
|
|
|
Quando o Google redireciona de volta para:
|
|
```
|
|
https://n8n.automatizase.com.br/rest/oauth2-credential/callback?code=...&state=...
|
|
```
|
|
|
|
O n8n:
|
|
1. Lê o `state`
|
|
2. Procura a credencial com esse ID
|
|
3. Atualiza a credencial com os tokens OAuth
|
|
|
|
Se o `state` não for um `credential_id` válido do n8n, ele retorna "Invalid state format".
|
|
|
|
## Solução
|
|
|
|
### 1. Usar credential_id no state
|
|
|
|
**Dashboard (`app/dashboard/page.tsx`):**
|
|
```typescript
|
|
const n8nCredentialId = process.env.NEXT_PUBLIC_N8N_CREDENTIAL_ID;
|
|
const state = n8nCredentialId; // ID da credencial n8n
|
|
```
|
|
|
|
### 2. Pegar user_id da sessão no callback
|
|
|
|
**Callback (`app/api/google-calendar/callback/route.ts`):**
|
|
```typescript
|
|
// Criar cliente Supabase com cookies
|
|
const cookieStore = await cookies();
|
|
const supabase = createServerClient(..., {
|
|
cookies: { ... }
|
|
});
|
|
|
|
// Pegar user da sessão
|
|
const { data: { user } } = await supabase.auth.getUser();
|
|
|
|
// Salvar no banco usando user.id (não o state)
|
|
await supabase.schema("portal").from("integrations").upsert({
|
|
user_id: user.id,
|
|
provider: "google_calendar",
|
|
status: "connecting",
|
|
...
|
|
});
|
|
```
|
|
|
|
## Fluxo Correto
|
|
|
|
```
|
|
1. Dashboard:
|
|
state = credential_id (ex: "ccTThTS9TKsejR7W")
|
|
|
|
2. Google OAuth:
|
|
Redireciona com state=credential_id
|
|
|
|
3. Callback Dashboard:
|
|
- Lê state (credential_id)
|
|
- Lê user_id da sessão Supabase
|
|
- Salva no banco: user_id + status
|
|
- Redireciona para n8n com state=credential_id
|
|
|
|
4. n8n:
|
|
- Lê state (credential_id)
|
|
- Atualiza credencial com tokens OAuth
|
|
- Sucesso!
|
|
```
|
|
|
|
## Variáveis de Ambiente Necessárias
|
|
|
|
```bash
|
|
# Google OAuth
|
|
NEXT_PUBLIC_GOOGLE_CLIENT_ID=your-client-id.apps.googleusercontent.com
|
|
|
|
# n8n Credential ID (IMPORTANTE!)
|
|
NEXT_PUBLIC_N8N_CREDENTIAL_ID=ccTThTS9TKsejR7W
|
|
|
|
# n8n Base URL
|
|
N8N_BASE_URL=https://n8n.automatizase.com.br
|
|
```
|
|
|
|
## Como encontrar o Credential ID?
|
|
|
|
### Opção 1: URL do n8n
|
|
1. Acesse n8n → Credentials
|
|
2. Clique na credencial Google Calendar OAuth2
|
|
3. URL será: `https://n8n.automatizase.com.br/credentials/ccTThTS9TKsejR7W`
|
|
4. O ID é a última parte: `ccTThTS9TKsejR7W`
|
|
|
|
### Opção 2: API do n8n
|
|
```bash
|
|
curl https://n8n.automatizase.com.br/api/v1/credentials \
|
|
-H "X-N8N-API-KEY: your-api-key" | jq '.[] | select(.type == "googleCalendarOAuth2Api") | .id'
|
|
```
|
|
|
|
## Resumo
|
|
|
|
- ❌ **ERRADO:** `state = user_id` (UUID)
|
|
- ✅ **CORRETO:** `state = credential_id` (ID do n8n)
|
|
- ✅ **user_id:** Pegar da sessão Supabase no callback
|
|
|
|
O `state` é para o **n8n identificar a credencial**.
|
|
O `user_id` é para o **dashboard salvar no banco**.
|