Parâmetros do corpo da requisição para token de atualização no fluxo OAuth

Estou tentando conectar a uma API externa usando o fluxo OAuth com a abordagem de arquivos de credencial para um nó personalizado. O problema que tenho é que para o servidor OAuth durante a atualização do token, preciso enviar o parâmetro resource como um parâmetro de corpo para obter um token de acesso atualizado adequadamente.

Alguém já enfrentou esse tipo de cenário? Os parâmetros de corpo padrão não são suficientes.

@shamika o helper de credencial OAuth2 padrão no n8n não expõe customização de refresh-body pronta para usar, mas existem alguns caminhos dependendo de qual servidor você está direcionando.

se é especificamente Microsoft/Azure AD (caso mais comum para precisar do parâmetro resource body), a solução mais limpa a longo prazo é mudar dos endpoints v1.0 para v2.0 — Microsoft descontinuou o parâmetro resource anos atrás e o substituiu por scope com resource embutido. em vez de body resource=https://graph.microsoft.com, seu scope vira https://graph.microsoft.com/.default. o endpoint v2.0 é /oauth2/v2.0/token em vez de /oauth2/token. zero código customizado necessário se você conseguir mover os endpoints.

se você não consegue mover endpoints (alguns servidores OAuth enterprise/legado genuinamente requerem resource no body), o caminho para um nó customizado é NÃO estender oAuth2Api e em vez disso definir seu próprio tipo de credencial com IAuthenticateGeneric e tratar refresh manualmente:

{
  "name": "myCustomOAuth2Api",
  "displayName": "My Custom OAuth2",
  "properties": [
    {"displayName": "Client ID", "name": "clientId", "type": "string"},
    {"displayName": "Client Secret", "name": "clientSecret", "type": "string", "typeOptions": {"password": true}},
    {"displayName": "Resource", "name": "resource", "type": "string"}
  ],
  "authenticate": {
    "type": "generic",
    "properties": {
      "headers": {"Authorization": "=Bearer {{ $credentials.accessToken }}"}
    }
  }
}

depois no nó implemente o refresh do token manualmente via hook preSend verificando expiração e fazendo POST para a URL de token com seus parâmetros de body necessários (incluindo resource). adiciona complexidade mas te dá controle total do fluxo de refresh.

terceira opção se você quer manter estendendo oAuth2Api e só precisa de resource anexado — tente adicioná-lo como query param na accessTokenUrl em si, o fluxo padrão do n8n passa query params através na requisição de refresh também. por exemplo accessTokenUrl: https://login.example.com/token?resource=https://api.example.com. menos limpo mas o menor patch possível.

qual servidor OAuth você está conectando? Azure AD, Salesforce, Ping Identity, enterprise customizado? muda qual caminho é mais realista.

@achamm cobriu bem os caminhos principais. Uma adição prática: antes de seguir a rota IAuthenticateGeneric, primeiro confirme qual servidor OAuth você está direcionando. Se for um servidor moderno (Azure AD, Google, Okta), o endpoint v2 baseado em scope é quase sempre a escolha certa e não requer nenhum código personalizado. Se for um servidor OAuth legado ou on-premise que genuinamente requer resource como parâmetro no corpo da requisição - é aí que IAuthenticateGeneric + hook preSend manual é a solução mais limpa. Você pode compartilhar qual serviço/servidor OAuth você está conectando? Isso vai ajudar a estreitar para o caminho certo.

Oi @achamm, obrigado pela resposta detalhada. O servidor OAuth é um servidor personalizado auto-hospedado de um cliente. Para contexto, o access token é um JWT, então durante a atualização, como um resource não foi especificado, recebi um token opaco em vez de um JWT. Mas no code exchange inicial, como os parâmetros do body podem ser enviados via ‘sendAdditionalBodyProperties’, consegui um JWT.

Usei o Postman para obter um refresh token manualmente com o parâmetro resource no body e recebi um JWT perfeito, então confirma que o parâmetro resource faz a diferença.

Um token opaco não é viável, já que o serviço a ser desenvolvido será serverless e a autenticação precisa ser auto-contida. Prefiro uma solução limpa aqui, pois vou precisar manter isso para o cliente.

Duas opções que estou considerando são a opção de parâmetro de query, mas ainda não sei se o servidor se adequa a isso. A outra é a lógica de refresh personalizada. Você já viu algum node que tenha implementado esse tipo de mecanismo de refresh token personalizado como referência?

@shamika a referência existente mais limpa é o community node n8n-nodes-azure-openai-ms-oauth2 no npm — ele implementa exatamente esse padrão (custom MS OAuth refresh com parâmetro resource no corpo da requisição) NÃO estendendo oAuth2Api e, em vez disso, gerenciando o ciclo de vida do token no hook preSend do node. para seu flow custom-server é aproximadamente ~50 linhas de TypeScript: armazenar accessToken/refreshToken/expiresAt na credencial, verificar expiração em preSend, fazer POST para seu endpoint de token com o corpo resource quando expirado, atualizar o token em cache antes de encaminhar a requisição real.

vale a pena tentar a rota query-param primeiro, já que é zero código — o flow OAuth2Api padrão do n8n passa query params de URL para a requisição de refresh, então se você definir accessTokenUrl como https://seu-servidor/token?resource=https://api.target.com e seu servidor OAuth aceita resource tanto do corpo quanto de query, isso funciona sem fazer fork de nada. depende inteiramente de se seu servidor é rigoroso apenas com corpo.

se for rigoroso com corpo-only, o source do n8n-nodes-azure-openai-ms-oauth2 é o blueprint — faça um fork dele, troque os endpoints/scopes específicos da MS pelos do seu servidor, distribua como um community node privado. muito mais limpo a longo prazo do que um hack com Code node.

bem vindo à comunidade n8n @shamika
pode por favor compartilhar seu json sem os dados sensíveis ?

Já fiz exatamente isso antes. A recomendação de achamm sobre n8n-nodes-azure-openai-ms-oauth2 é a referência mais limpa se você estiver criando um nó customizado — gerencia o ciclo de vida completo do token no hook preSend do próprio nó e adiciona o parâmetro do corpo do recurso na atualização exatamente como você precisa. O código está no npm e GitHub, fácil de fazer fork.

Se você quer um template de starter ainda mais simples para consultar, o nó built-in do Google Drive do n8n tem lógica customizada de OAuth2 na definição de credencial que gerencia a atualização de token com parâmetros extras (está no repositório core do n8n em packages/nodes-base/credentials/GoogleOAuth2Api.credentials.ts). O padrão é quase idêntico: armazena tokens, verifica expiração, faz POST no endpoint de token com quaisquer campos de corpo extras que você precise, atualiza o token de acesso antes da requisição real sair.

Para seu caso específico — servidor OAuth customizado, precisa de recurso no corpo — a lógica de preSend seria mais ou menos assim (dentro do método execute ou preSend do seu nó customizado):

async preSend(request, options) {

const credentials = await this.getCredentials(‘myCustomOAuth2Api’);

// Verifica se o token expirou

if (Date.now() > credentials.expiresAt) {

const refreshParams = new URLSearchParams({

  grant_type: 'refresh_token',

  refresh_token: credentials.refreshToken,

  client_id: credentials.clientId,

  client_secret: credentials.clientSecret,

  resource: credentials.resource, // o parâmetro crucial do corpo

});

const tokenResponse = await this.helpers.httpRequest({

  method: 'POST',

  url: credentials.accessTokenUrl,

  body: refreshParams.toString(),

  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },

});

// Atualiza o cache de credenciais

credentials.accessToken = tokenResponse.access_token;

credentials.refreshToken = tokenResponse.refresh_token;

credentials.expiresAt = Date.now() + (tokenResponse.expires_in * 1000);

await this.setCredentials('myCustomOAuth2Api', credentials);

}

// Anexa token de acesso à requisição original

request.headers.Authorization = Bearer ${credentials.accessToken};

return request;

}

Esse é basicamente o esquema. Para produção, você adicionaria tratamento de erros e armazenamento de tokens apropriadamente (o objeto de credenciais do n8n persiste via banco de dados automaticamente).

Mas antes de escrever uma única linha de código — tente primeiro o truque do parâmetro de query. Apenas adicione ?resource=https://seu-alvo à sua accessTokenUrl. Se o servidor aceitar como parâmetro de query, você terminou em 10 segundos. Muitos servidores OAuth customizados aceitam, porque analisam ambos. Se for estritamente corpo apenas, então a rota de nó customizado é sólida e mantível a longo prazo.

Me avise qual caminho você acaba tomando — fico feliz em ajudar a debugar o hook preSend se você travar.

Oi, para quem está acompanhando isto, aqui está uma atualização. Como o servidor de autenticação era customizado, conseguimos inserir o parâmetro de recurso no corpo do endpoint de token a partir de um proxy confiável. Portanto, não fizemos nenhuma alteração no fluxo padrão do n8n.

Oi, obrigado pela resposta. Fiz uma atualização de resposta no caso que adicionei. Conseguimos resolver isso usando uma abordagem de proxy confiável em vez de um fluxo de credencial n8n personalizado. Acredito que essa abordagem é mais limpa e melhor em termos de manutenibilidade.