El mensaje acaba en un salto de línea, y también se firma. Si la firma no te cuadra, prueba a quitarlo.

HMAC-${ nombreAlgoritmo }
${ f[1] }

Escribe la clave y el mensaje, o .

${ verificacion.texto }

¿Qué es un HMAC?

Un HMAC (Hash-based Message Authentication Code) es una firma que se calcula con un mensaje y una clave secreta, usando por dentro una función hash como SHA-256. Quien tenga la misma clave puede volver a calcularla y comprobar dos cosas a la vez: que el mensaje no se ha modificado por el camino y que lo ha enviado alguien que conoce la clave.

Se diferencia de un hash normal en la clave: el SHA-256 de un mensaje lo puede calcular cualquiera, pero su HMAC-SHA256 solo quien tenga la clave. Y se diferencia de una firma digital (RSA, ECDSA) en que la clave es la misma para firmar y para comprobar, así que solo sirve entre dos partes que confían entre sí.

Comprobar la firma de un webhook

Cuando un servicio te avisa de algo enviando una petición a tu web (un webhook), firma el cuerpo con un HMAC y una clave que compartís, para que puedas rechazar las peticiones falsas. Cada uno lo hace a su manera:

ServicioCabeceraQué se firmaFormato
GitHubX-Hub-Signature-256El cuerpo de la peticiónsha256= y la firma en hex
StripeStripe-SignatureEl valor t, un punto y el cuerpo: t.cuerpoHex, en v1=
ShopifyX-Shopify-Hmac-Sha256El cuerpo de la peticiónBase64
SlackX-Slack-Signaturev0:, la marca de tiempo, dos puntos y el cuerpov0= y la firma en hex

Todos usan HMAC-SHA256. Para probar a mano, copia el cuerpo exacto de la petición (sin formatearlo ni añadirle un salto de línea al final), pega tu clave y compara la firma con la de la cabecera. Si no cuadra, casi siempre es porque el cuerpo no es idéntico byte a byte al que se firmó.

Consejos para tu código

  • Calcula la firma sobre el cuerpo tal cual llega, antes de decodificar el JSON: al volver a convertirlo en texto cambian los espacios o el orden y la firma deja de coincidir.
  • Compara las firmas con una función de tiempo constante, como hash_equals() en PHP o crypto.timingSafeEqual() en Node.js, y no con ==.
  • Si el servicio envía una marca de tiempo, rechaza las peticiones antiguas para que nadie pueda reenviar una petición válida capturada.
  • Guarda la clave como un secreto, en variables de entorno, nunca en el código ni en el repositorio.

Los tokens JWT firmados con HS256 también usan HMAC-SHA256, con la firma en Base64url. Puedes comprobarlos con el decodificador de JWT.

Copiado al portapapeles.