Gerador de HMAC e validador de webhook
Calcule HMAC-SHA256, SHA-384, SHA-512 ou SHA-1 e confira se a assinatura recebida no webhook bate. Os modelos de GitHub, Stripe, Shopify, Mercado Pago e Slack já montam a mensagem assinada do jeito de cada um. Payload e chave ficam no navegador.
HMAC do payload como está, com o algoritmo e a codificação que você escolher.
A assinatura cobre o corpo bruto, byte a byte. Um espaço, uma quebra de linha ou a ordem dos campos diferente já muda o resultado. Cole o corpo exatamente como chegou, antes de passar por JSON.parse ou por um formatador.
Assinatura
Falta a chave
Informe a chave secreta. A assinatura aparece enquanto você digita.
Um JWT HS256 é um HMAC-SHA256 do header e do payload. O decodificador confere a assinatura do token com o seu segredo.
Quer ler o payload do webhook? Formate numa aba separada. O JSON formatado tem outros bytes e não serve para conferir a assinatura.
Precisa só do hash, sem chave? O gerador de hash calcula MD5, SHA-1 e SHA-256 de texto e arquivo.
O que é HMAC
HMAC é um hash calculado com uma chave secreta (RFC 2104). Um SHA-256 comum qualquer pessoa recalcula depois de alterar a mensagem. Com HMAC, só quem conhece a chave consegue produzir a assinatura certa. Por isso ele é usado para provar que uma requisição veio de quem diz e não foi alterada no caminho: webhooks, assinatura de API como a AWS Signature V4 e tokens JWT HS256.
Formato de cada provedor
Cada provedor escolhe o que assina e como escreve o resultado. A tabela resume os modelos desta página; o formato foi conferido na documentação oficial de cada um.
| Provedor | Header | O que é assinado | Formato |
|---|---|---|---|
| GitHub | X-Hub-Signature-256 | corpo | sha256=<hex> |
| Stripe | Stripe-Signature | t.corpo | t=<ts>,v1=<hex> |
| Shopify | X-Shopify-Hmac-Sha256 | corpo | <base64> |
| Mercado Pago | x-signature | id:…;request-id:…;ts:…; | ts=<ts>,v1=<hex> |
| Slack | X-Slack-Signature | v0:timestamp:corpo | v0=<hex> |
Como a verificação de webhook funciona
O provedor e a sua aplicação guardam o mesmo segredo. Ao enviar o evento, o provedor calcula o HMAC do corpo, ou de uma mensagem montada com timestamp e corpo, e manda o resultado num header. Sua aplicação recalcula com o corpo recebido e compara. Se bater, o evento é autêntico. A comparação deve ser em tempo constante, com crypto.timingSafeEqual no Node, hash_equals no PHP ou hmac.compare_digest no Python, para não vazar a assinatura pelo tempo de resposta.
O motivo número um de assinatura inválida
O framework converte o JSON em objeto antes do seu código, e ao serializar de novo a ordem das chaves, os espaços e o escape de acentos mudam. A assinatura deixa de bater mesmo com a chave certa. Leia o corpo bruto: express.raw() no Express, $request->getContent() no Laravel, um parâmetro String com @RequestBody no Spring e request.get_data() no Flask. No NestJS, crie a aplicação com rawBody: true e use req.rawBody.
Chave em texto, hex ou Base64
O HMAC trabalha com os bytes da chave. Se o painel do provedor mostra um segredo em hex e você usa essa string como texto, os bytes são outros e a assinatura também. A maioria dos provedores de webhook, incluindo GitHub, Stripe, Shopify, Mercado Pago e Slack, usa o segredo como texto, do jeito que aparece no painel, incluindo o prefixo whsec_ da Stripe.
Timestamp e reenvio
Uma requisição válida capturada continua válida se for reenviada. Stripe e Slack colocam o timestamp dentro da mensagem assinada, e as bibliotecas deles recusam eventos com mais de 5 minutos. Ao testar com um payload antigo copiado do log, a assinatura pode bater aqui e mesmo assim ser recusada pelo seu servidor por causa do horário.
Perguntas frequentes sobre HMAC
Assinatura de webhook, chave, codificação e os erros mais comuns na validação.