Verificar la firma HMAC de los webhooks salientes (lado receptor)
Cómo validar en tu propio servidor que un webhook saliente de Omnifox es auténtico, usando la firma HMAC-SHA256.
Cuando configurás un Webhook saliente en Omnifox (Configuración > Webhooks), cada evento (contact.created, message.delivered, conversation.assigned, etc.) se envía por HTTP POST a la URL que definiste. Para que tu servidor pueda confirmar que ese POST realmente vino de Omnifox y no de un tercero, cada entrega incluye una firma HMAC-SHA256.
Requisitos
- Un Webhook creado en
Configuración > Webhooks, con URL HTTPS (obligatorio). - El
signing_secret(con prefijowhsec_) que Omnifox te muestra una sola vez al crear el webhook o al rotarlo (POST /api/v1/webhooks/{webhook}/rotate-secret). Guardalo de inmediato en un lugar seguro: no se puede volver a consultar.
Encabezados que recibís en cada entrega
| Encabezado | Contenido |
|---|---|
X-Omnifox-Event |
Nombre del evento, ej. message.delivered |
X-Omnifox-Delivery-Id |
ID único de esa entrega (útil para deduplicar reintentos) |
X-Omnifox-Timestamp |
Timestamp Unix (segundos) en que se firmó el payload |
X-Omnifox-Signature |
sha256=<hex> — la firma HMAC |
X-Omnifox-Attempt |
Número de intento (1 = primer intento) |
Cómo se calcula la firma
firma = HMAC_SHA256( "{timestamp}.{cuerpo_json_exacto}" , signing_secret )
El timestamp es el mismo valor del encabezado X-Omnifox-Timestamp, unido con un punto (.) al cuerpo JSON tal cual llegó (sin reformatear ni reordenar claves).
Ejemplo: verificación en Node.js
const crypto = require('crypto');
function verifyOmnifoxWebhook(rawBody, headers, signingSecret) {
const signatureHeader = headers['x-omnifox-signature'] || '';
const timestamp = headers['x-omnifox-timestamp'] || '';
const [, providedHex] = signatureHeader.split('=');
const expectedHex = crypto
.createHmac('sha256', signingSecret)
.update(`${timestamp}.${rawBody}`)
.digest('hex');
const valid = providedHex &&
crypto.timingSafeEqual(Buffer.from(expectedHex), Buffer.from(providedHex));
return valid;
}
Usá siempre el cuerpo crudo (raw body, string sin parsear) para calcular la firma; si tu framework ya parseó el JSON, tenés que capturar el raw body antes.
Consejos
- Rechazá (HTTP 401) cualquier entrega cuya firma no coincida, antes de procesar el payload.
- Agregá una validación opcional de "replay": si
X-Omnifox-Timestamptiene más de unos minutos de antigüedad, rechazá la entrega. - Usá
X-Omnifox-Delivery-Idpara deduplicar: Omnifox reintenta entregas con backoff exponencial si tu endpoint responde con error o timeout, así que podés recibir el mismo evento más de una vez.
Solución de problemas
- La firma nunca coincide: lo más común es comparar contra el JSON re-serializado por tu framework en vez del cuerpo crudo exacto que llegó.
- No llegan los encabezados de firma: si el webhook se creó antes de rotar/generar
signing_secret, algunas suscripciones antiguas quedan sin firmar (legado); rotá el secreto desdeConfiguración > Webhookspara activarla. - Perdiste el
signing_secret: no hay forma de recuperarlo; rotalo conPOST /api/v1/webhooks/{webhook}/rotate-secrety actualizá tu verificación con el nuevo valor.
Artículos relacionados
-
Cómo conectar integraciones y apps externas
Conecta Omnifox con tus herramientas favoritas desde el catálogo de integraciones en pocos pasos.
-
Generar y usar API keys y webhooks
Crea claves de API para acceder a Omnifox por código y configura webhooks para recibir eventos en tiempo real.
-
Introducción a las integraciones (webhook / OAuth / API key)
Conecta Omnifox con tus otras herramientas. Aprende cuándo usar un webhook, una conexión OAuth de la galería o una clave de API.
-
La API REST de Omnifox: introducción y requisitos de plan
Qué es la API REST de Omnifox, qué plan necesitas (desde Crece), cómo autenticar con la cabecera X-API-Key y dónde está la documentación.
-
Crear una clave API personal (PAT)
Aprendé a generar tu primera clave API personal en Omnifox para conectar integraciones, scripts o herramientas externas a tu workspace.