Configurar Webhooks
Los webhooks permiten que tu aplicación reciba notificaciones HTTP en tiempo real cuando ocurren eventos en Auris, como el registro de un usuario, un fallo de inicio de sesión, la asignación de un rol o la creación de una organización. En lugar de consultar la API periódicamente para detectar cambios, Auris envía los payloads de eventos a tu endpoint en el momento en que suceden.
Esta guía te muestra cómo crear un receptor de webhooks, registrarlo en la Consola de Auris, verificar firmas por seguridad y gestionar fallos de forma adecuada.
Por Qué Usar Webhooks
Sin webhooks, tu aplicación tendría que consultar las APIs de Auris repetidamente para detectar cambios. Esto es ineficiente, introduce latencia (solo detectas los cambios en el siguiente ciclo de consulta) y desperdicia recursos en ambos lados. Los webhooks invierten este modelo: Auris notifica a tu aplicación de inmediato cuando ocurre algo.
Casos de uso habituales:
- Sincronizar datos de usuario en tu base de datos cuando se crea o actualiza un usuario
- Activar flujos de incorporación cuando se registra un nuevo usuario
- Revocar acceso en tu sistema cuando un usuario es deshabilitado o eliminado
- Auditoría transmitiendo eventos a tu SIEM
- Notificaciones en Slack/Teams cuando se detecta actividad de inicio de sesión sospechosa
Paso 1: Crear un Endpoint Webhook en Tu Aplicación
Tu endpoint webhook es un manejador HTTP POST estándar que recibe payloads JSON de Auris. A continuación se muestra un ejemplo completo con Express.js y verificación de firma:
import express from 'express'
import crypto from 'crypto'
const app = express()
// IMPORTANTE: Usar el cuerpo sin procesar para la verificación de firma
app.post(
'/webhooks/auris',
express.raw({ type: 'application/json' }),
(req, res) => {
const signature = req.headers['x-webhook-signature'] as string
const timestamp = req.headers['x-webhook-timestamp'] as string
const secret = process.env.AURIS_WEBHOOK_SECRET! // ej. whsec_abc123...
// 1. Verificar la firma
if (!verifyWebhookSignature(req.body, signature, timestamp, secret)) {
console.error('Verificación de firma del webhook fallida')
return res.status(401).json({ error: 'Firma inválida' })
}
// 2. Parsear el evento
const event = JSON.parse(req.body.toString())
console.log(`Evento recibido: ${event.type}`, event.data)
// 3. Responder 200 inmediatamente — procesar de forma asíncrona
res.status(200).json({ received: true })
// 4. Manejar el evento de forma asíncrona
handleWebhookEvent(event).catch((err) =>
console.error('Error en el manejador de webhook:', err)
)
}
)
function verifyWebhookSignature(
body: Buffer,
signature: string,
timestamp: string,
secret: string
): boolean {
// Rechazar si el timestamp tiene más de 5 minutos (protección contra repetición)
const eventTime = parseInt(timestamp, 10)
const now = Math.floor(Date.now() / 1000)
if (Math.abs(now - eventTime) > 300) {
return false
}
// Calcular la firma esperada: HMAC-SHA256(timestamp.body)
const payload = `${timestamp}.${body.toString()}`
const expected = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex')
// Comparación en tiempo constante para prevenir ataques de temporización
try {
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
)
} catch {
return false
}
}
async function handleWebhookEvent(event: {
type: string
data: Record<string, unknown>
}) {
switch (event.type) {
case 'user.created':
// Sincronizar usuario en la base de datos local
await syncUser(event.data)
break
case 'user.deleted':
// Eliminar datos del usuario del sistema
await removeUser(event.data)
break
case 'login.suspicious':
// Alertar al equipo de seguridad
await notifySecurityTeam(event.data)
break
default:
console.log(`Tipo de evento no gestionado: ${event.type}`)
}
}
app.listen(3000, () => console.log('Servidor de webhooks ejecutándose en el puerto 3000'))Utiliza siempre el cuerpo de la solicitud sin procesar (no el objeto JSON parseado) al calcular la firma HMAC. Parsear y volver a serializar el JSON puede cambiar los espacios en blanco o el orden de las claves, lo que invalidaría la firma.
Paso 2: Registrar el Webhook en la Consola de Auris
- Abre la Consola de Auris y navega a Configuración y luego a Webhooks
- Haz clic en Crear Webhook
- Introduce la URL de tu endpoint (ej.
https://api.yourapp.com/webhooks/auris) - Selecciona los eventos que deseas recibir (o elige “Todos los eventos”)
- Haz clic en Crear
Auris genera un secreto de firma con el prefijo whsec_ (ej. whsec_k7Gm2x9pQ...). Copia este valor de inmediato y guárdalo de forma segura en tus variables de entorno. El secreto completo solo se muestra una vez.
También puedes registrar webhooks a través de la API:
curl -X POST https://auth.yourdomain.com/api/webhooks \
-H "Authorization: Bearer $AURIS_ACCESS_TOKEN" \
-H "x-tenant: your-tenant-id" \
-H "Content-Type: application/json" \
-d '{
"name": "Webhook de producción",
"url": "https://api.yourapp.com/webhooks/auris",
"events": ["user.created", "user.updated", "user.deleted", "login.failed"],
"isActive": true
}'Respuesta:
{
"ok": true,
"data": {
"id": "whk_abc123",
"name": "Webhook de producción",
"url": "https://api.yourapp.com/webhooks/auris",
"events": ["user.created", "user.updated", "user.deleted", "login.failed"],
"signingSecret": "whsec_k7Gm2x9pQzR4vL8...",
"isActive": true,
"createdAt": "2026-01-15T10:00:00Z"
}
}Paso 3: Verificar Firmas de Webhook
Cada entrega de webhook de Auris incluye dos cabeceras para la verificación:
| Cabecera | Descripción |
|---|---|
X-Webhook-Signature | Resumen hexadecimal HMAC-SHA256 del payload |
X-Webhook-Timestamp | Timestamp Unix (segundos) en que se envió el evento |
La firma se calcula como:
HMAC-SHA256(whsec_secret, "${timestamp}.${rawBody}")Algoritmo de Verificación
- Extraer las cabeceras
X-Webhook-SignatureyX-Webhook-Timestampde la solicitud - Comprobar que el timestamp está dentro de los 5 minutos del tiempo actual (protección contra repetición)
- Concatenar el timestamp, un punto literal (
.) y el cuerpo de la solicitud sin procesar - Calcular el HMAC-SHA256 de esa cadena usando tu secreto de firma
whsec_ - Comparar la firma calculada con la firma recibida usando una función de comparación en tiempo constante
A continuación se muestra una función de verificación independiente en TypeScript:
import crypto from 'crypto'
export function verifyAurisWebhook(
rawBody: string | Buffer,
signature: string,
timestamp: string,
secret: string
): boolean {
// Paso 1: Protección contra repetición — rechazar eventos con más de 5 minutos de antigüedad
const ts = parseInt(timestamp, 10)
if (isNaN(ts) || Math.abs(Date.now() / 1000 - ts) > 300) {
return false
}
// Paso 2: Calcular la firma esperada
const body = typeof rawBody === 'string' ? rawBody : rawBody.toString('utf-8')
const payload = `${timestamp}.${body}`
const expected = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex')
// Paso 3: Comparación en tiempo constante
try {
return crypto.timingSafeEqual(
Buffer.from(signature, 'utf-8'),
Buffer.from(expected, 'utf-8')
)
} catch {
return false
}
}Usar el SDK de Auris para la Verificación
Si utilizas @auris/js, el SDK incluye una utilidad integrada de verificación de webhooks:
import { verifyWebhookSignature } from '@auris/js/webhooks'
const isValid = await verifyWebhookSignature({
payload: rawBody,
signature: req.headers['x-webhook-signature'],
timestamp: req.headers['x-webhook-timestamp'],
secret: process.env.AURIS_WEBHOOK_SECRET!,
})Nunca omitas la verificación de firma en producción. Sin ella, cualquier atacante que descubra la URL de tu endpoint puede enviar eventos falsificados a tu aplicación.
Catálogo de Eventos
Auris envía eventos organizados en las siguientes categorías. Cada payload de evento incluye un campo type (ej. user.created) y un objeto data con el recurso correspondiente.
Eventos de Usuario
| Evento | Se activa cuando |
|---|---|
user.created | Se registra un nuevo usuario (registro, creación por administrador, aprovisionamiento SCIM o SSO JIT) |
user.updated | Se modifican campos del perfil del usuario |
user.deleted | Un usuario es eliminado de forma suave |
user.email_verified | Un usuario verifica su dirección de correo electrónico |
user.password_changed | Un usuario cambia su contraseña |
user.blocked | Una cuenta de usuario es deshabilitada |
user.unblocked | Una cuenta de usuario es rehabilitada |
Eventos de Inicio de Sesión
| Evento | Se activa cuando |
|---|---|
login.succeeded | Un usuario se autentica correctamente |
login.failed | Un intento de inicio de sesión falla (credenciales incorrectas, cuenta bloqueada, etc.) |
login.mfa_required | Se activa el paso de MFA durante el inicio de sesión |
login.suspicious | Un inicio de sesión es marcado por la detección de actividad sospechosa |
Eventos de Roles y Permisos
| Evento | Se activa cuando |
|---|---|
role.created | Se crea un nuevo rol |
role.updated | Se modifican el nombre, la descripción o los permisos de un rol |
role.deleted | Se elimina un rol |
role.assigned | Se asigna un rol a un usuario |
role.unassigned | Se elimina un rol de un usuario |
Eventos de Organización
| Evento | Se activa cuando |
|---|---|
organization.created | Se crea una nueva organización |
organization.updated | Se modifican los detalles de una organización |
organization.deleted | Se elimina una organización |
organization.member_added | Un usuario se une a una organización |
organization.member_removed | Un usuario es eliminado de una organización |
organization.invitation_sent | Se envía una invitación |
organization.invitation_accepted | Se acepta una invitación |
Eventos de Aplicación
| Evento | Se activa cuando |
|---|---|
application.created | Se registra una nueva aplicación |
application.updated | Se modifica la configuración de una aplicación |
application.secret_rotated | Se rota el secreto de cliente de una aplicación |
Ejemplo de Payload
{
"id": "evt_abc123def456",
"type": "user.created",
"timestamp": "2026-01-15T10:30:00Z",
"data": {
"id": "usr_xyz789",
"email": "[email protected]",
"firstName": "Jane",
"lastName": "Doe",
"emailVerified": false,
"roles": [],
"createdAt": "2026-01-15T10:30:00Z"
}
}Gestión de Fallos y Reintentos
Si tu endpoint devuelve un código de estado distinto a 2xx o no responde en 30 segundos, Auris considera que la entrega ha fallado y reintenta con retroceso exponencial:
| Intento | Retraso tras el fallo |
|---|---|
| 1er reintento | 1 minuto |
| 2º reintento | 5 minutos |
| 3er reintento | 30 minutos |
| 4º reintento | 2 horas |
| 5º reintento | 12 horas |
Tras 5 reintentos fallidos (6 intentos en total), la entrega se marca como fallida permanentemente. Puedes ver las entregas fallidas y reintentarlas manualmente en la Consola en Configuración → Webhooks → selecciona un webhook → Entregas.
Si un endpoint webhook falla de forma continua, Auris deshabilita automáticamente el webhook tras 10 entregas consecutivas fallidas y envía una notificación a los administradores del tenant. Vuelve a habilitarlo desde la Consola tras resolver el problema subyacente.
Probar Webhooks
Botón de Prueba en la Consola
En la Consola de Auris, cada webhook dispone de un botón Probar que envía un evento sintético a tu endpoint. Es la forma más rápida de verificar que tu endpoint es accesible y que la verificación de firma funciona correctamente.
Desarrollo Local con ngrok
Durante el desarrollo, tu servidor local no es accesible públicamente. Usa una herramienta de tunelización como ngrok para exponerlo:
# Iniciar el servidor de webhooks local
node server.js # o: npx ts-node server.ts
# En otra terminal, iniciar ngrok
ngrok http 3000ngrok proporciona una URL pública como https://a1b2c3d4.ngrok-free.app. Usa esta URL al registrar el webhook en la Consola:
https://a1b2c3d4.ngrok-free.app/webhooks/aurisTras registrarlo, usa el botón de prueba de la Consola o activa un evento real (ej. crear un usuario) para ver el payload llegar a tu servidor local.
Inspeccionar Entregas
La página de detalle de webhook en la Consola muestra un registro de entregas con:
- Código de estado HTTP devuelto por tu endpoint
- Cuerpo de la respuesta (primeros 1 KB)
- Tiempo de respuesta en milisegundos
- Número de reintentos realizados
- Timestamp de cada intento de entrega
Buenas Prácticas
Responde 200 de inmediato. Tu endpoint debe devolver HTTP 200 lo antes posible y luego procesar el evento de forma asíncrona (ej. encolándolo). Si el manejador tarda demasiado, Auris puede agotar el tiempo de espera y reintentar, lo que puede provocar procesamiento duplicado.
Implementa idempotencia. Cada evento incluye un campo id único. Guarda los IDs de los eventos procesados y omite los duplicados. Los reintentos pueden entregar el mismo evento varias veces.
async function handleWebhookEvent(event: { id: string; type: string; data: unknown }) {
// Comprobar si ya fue procesado
const exists = await db.processedWebhookEvent.findUnique({
where: { eventId: event.id },
})
if (exists) {
console.log(`Omitiendo evento duplicado: ${event.id}`)
return
}
// Procesar el evento
await processEvent(event)
// Marcar como procesado
await db.processedWebhookEvent.create({
data: { eventId: event.id, processedAt: new Date() },
})
}Usa endpoints HTTPS. Auris solo envía payloads de webhook por HTTPS. Los endpoints HTTP son rechazados al registrar el webhook.
Rota los secretos periódicamente. Usa la Consola o la API para rotar tu secreto de firma del webhook. Auris admite la rotación de secretos con un período de gracia en el que se aceptan tanto el secreto antiguo como el nuevo.
curl -X POST https://auth.yourdomain.com/api/webhooks/whk_abc123/rotate-secret \
-H "Authorization: Bearer $AURIS_ACCESS_TOKEN" \
-H "x-tenant: your-tenant-id"Monitoriza el estado de las entregas. Configura alertas sobre la tasa de errores de tu endpoint. Si observas un pico en las entregas fallidas, revisa los logs de tu servidor y el registro de entregas de la Consola.
Filtra eventos al registrar. Suscríbete solo a los eventos que necesita tu aplicación. Suscribirse a todos los eventos genera tráfico y carga de procesamiento innecesarios.
Guías Relacionadas
- Streaming de Logs — Transmite logs de auditoría a servicios externos como Datadog y Splunk
- Motor de Acciones — Ejecuta lógica personalizada durante los flujos de autenticación
- Protección contra Ataques — Pipeline de seguridad y detección de inicios de sesión sospechosos