Parámetros del cuerpo para solicitud de token de actualización en flujo OAuth

Estoy intentando conectarme a una API externa utilizando el flujo OAuth con un enfoque de archivos de credenciales para un nodo personalizado. El problema que tengo es que para el servidor OAuth durante la actualización del token, necesito enviar el parámetro resource como un parámetro en el cuerpo para obtener un token de acceso actualizado apropiadamente.

¿Hay alguien que haya manejado este tipo de escenario? Los parámetros estándar del cuerpo no son suficientes.

@shamika el ayudante de credenciales OAuth2 estándar en n8n no expone la personalización de refresh-body por defecto, pero hay varios caminos dependiendo de qué servidor estés apuntando.

si es específicamente Microsoft/Azure AD (el caso más común para necesitar el parámetro resource body), la solución más limpia a largo plazo es cambiar de endpoints v1.0 a v2.0 — Microsoft deprecó el parámetro resource hace años y lo reemplazó con scope-con-resource-integrado. en lugar de body resource=https://graph.microsoft.com, tu scope se convierte en https://graph.microsoft.com/.default. el endpoint v2.0 es /oauth2/v2.0/token en lugar de /oauth2/token. cero código personalizado necesario si puedes cambiar endpoints.

si no puedes cambiar endpoints (algunos servidores OAuth empresariales/legacy genuinamente requieren resource en body), el camino para un nodo personalizado es NO extender oAuth2Api y en su lugar definir tu propio tipo de credencial con IAuthenticateGeneric y manejar 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 }}"}
    }
  }
}

luego en el nodo implementa el token refresh manualmente vía el hook preSend verificando expiración y haciendo POST a la URL del token con tus parámetros body requeridos (incluyendo resource). añade complejidad pero te da control total del flujo de refresh.

tercer opción si quieres mantener extendiendo oAuth2Api y solo necesitas resource adjunto — intenta añadirlo como un parámetro query en el accessTokenUrl mismo, el flujo estándar de n8n también pasa query params a través en la solicitud de refresh también. ej accessTokenUrl: https://login.example.com/token?resource=https://api.example.com. menos limpio pero el parche más pequeño posible.

¿qué servidor OAuth estás conectando? Azure AD, Salesforce, Ping Identity, ¿empresa personalizada? cambia cuál camino es más realista.

@achamm cubrió bien los caminos principales. Una adición práctica: antes de ir por la ruta IAuthenticateGeneric, confirma primero cuál es el servidor OAuth al que te diriges. Si es un servidor moderno (Azure AD, Google, Okta), el endpoint v2 basado en scope es casi siempre la opción correcta y requiere cero código personalizado. Si es un servidor OAuth heredado u on-premise que genuinamente requiere resource como parámetro en el cuerpo de la solicitud, ahí es donde IAuthenticateGeneric + el hook preSend manual es la solución más limpia. ¿Puedes compartir cuál es el servicio o servidor OAuth al que te estás conectando? Eso ayudará a reducir el camino correcto.

Hola @achamm, gracias por la respuesta detallada. El servidor OAuth es un servidor personalizado autohospedado de un cliente. Para contextualizar, el token de acceso es un JWT, así que durante la actualización, ya que no se especifica un recurso, recibí un token opaco en lugar de un JWT. Pero en el intercambio de código inicial, ya que los parámetros del cuerpo se pueden enviar mediante ‘sendAdditionalBodyProperties’, obtuve un JWT.

Utilicé Postman para obtener manualmente un token de actualización con el parámetro de recurso en el cuerpo y luego obtuve un JWT perfecto, por lo que se confirma que el parámetro de recurso es lo que marca la diferencia.

Un token opaco no es viable ya que el servicio a desarrollar será serverless y la autenticación necesita estar autocontenida. Preferiría una solución limpia aquí ya que tengo que mantenerla para el cliente.

Dos opciones en las que estoy pensando son la opción de parámetro de consulta, pero aún no sé si el servidor la cumple. La otra es la lógica de actualización personalizada. ¿Has visto algún nodo que haya implementado este tipo de mecanismo de token de actualización personalizado como referencia?

@shamika la referencia más limpia existente es el nodo comunitario n8n-nodes-azure-openai-ms-oauth2 en npm — implementa exactamente este patrón (OAuth2 personalizado de MS con parámetro de recurso en el cuerpo) sin extender oAuth2Api e invece manejando el ciclo de vida del token en el hook preSend del nodo. para tu flujo de servidor personalizado son aproximadamente ~50 líneas de TypeScript: almacena accessToken/refreshToken/expiresAt en la credencial, verifica la expiración en preSend, POST a tu endpoint de token con el cuerpo del recurso cuando expire, actualiza el token en caché antes de reenviar la solicitud actual.

valela pena probar primero la ruta de parámetro de consulta ya que es código cero — el flujo OAuth2Api estándar de n8n sí pasa parámetros de consulta URL a través de la solicitud de actualización, así que si configuras accessTokenUrl a https://ur-server/token?resource=https://api.target.com y tu servidor OAuth acepta recurso del cuerpo o la consulta, eso simplemente funciona sin hacer un fork de nada. depende completamente de si tu servidor es estrictamente solo cuerpo.

si es estrictamente solo cuerpo, la fuente n8n-nodes-azure-openai-ms-oauth2 es el plano — hazle un fork, cambia los endpoints/scopes específicos de MS por los de tu servidor, publícalo como nodo comunitario privado. mucho más limpio a largo plazo que un hack de nodo Code.

bienvenido a la comunidad n8n @shamika
¿puedes por favor compartir tu json sin los datos sensibles?

He hecho exactamente esto antes. La recomendación de achamm sobre n8n-nodes-azure-openai-ms-oauth2 es la referencia más limpia si estás construyendo un nodo personalizado — gestiona el ciclo de vida completo del token en el hook preSend del nodo y agrega el parámetro del cuerpo del recurso en la actualización exactamente como lo necesitas. El código fuente está en npm y GitHub, fácil de hacer fork.

Si quieres una plantilla de inicio aún más simple para consultar, el nodo Google Drive integrado de n8n tiene lógica OAuth2 personalizada en su definición de credencial que maneja la actualización del token con parámetros adicionales (está en el repositorio principal de n8n bajo packages/nodes-base/credentials/GoogleOAuth2Api.credentials.ts). El patrón es casi idéntico: almacena tokens, verifica la expiración, hace POST al endpoint del token con los campos de cuerpo adicionales que necesites, actualiza el token de acceso antes de que se envíe la solicitud real.

Para tu caso específico — servidor OAuth personalizado, necesitas recurso en el cuerpo — la lógica de preSend se vería algo así (dentro del método execute o preSend de tu nodo personalizado):

async preSend(request, options) {

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

// Verificar si el token ha expirado

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, // el parámetro de cuerpo crucial

});

const tokenResponse = await this.helpers.httpRequest({

  method: 'POST',

  url: credentials.accessTokenUrl,

  body: refreshParams.toString(),

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

});

// Actualizar caché de credenciales

credentials.accessToken = tokenResponse.access_token;

credentials.refreshToken = tokenResponse.refresh_token;

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

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

}

// Adjuntar token de acceso a la solicitud original

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

return request;

}

Ese es esencialmente el plano. Para producción, agregarías manejo de errores y almacenamiento de tokens adecuadamente (el objeto de credenciales de n8n persiste automáticamente a través de la base de datos).

Pero antes de que escribas una sola línea de código — intenta primero el truco del parámetro de consulta. Solo añade ?resource=https://your-target a tu accessTokenUrl. Si el servidor lo acepta como parámetro de consulta, ¡terminaste en 10 segundos! Muchos servidores OAuth personalizados lo hacen, porque analizan ambos. Si es estrictamente solo cuerpo, entonces la ruta del nodo personalizado es sólida y mantenible a largo plazo.

Cuéntame qué camino terminas eligiendo — encantado de ayudarte a depurar el hook preSend si te quedas atascado.

Hola, para quien esté revisando esto, aquí hay una actualización al respecto. Dado que el servidor de autenticación era personalizado, pudimos enviar el parámetro de recurso al cuerpo del endpoint de token desde un proxy de confianza. Así que no hicimos ningún cambio en el flujo predeterminado de n8n.

Hola, gracias por la respuesta. Hice una respuesta actualizada en el caso que agregué. Pudimos resolver esto con un enfoque de proxy confiable en lugar de un flujo de credencial personalizado de n8n. Creo que ese enfoque es más limpio y mejor en términos de mantenibilidad.