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.

Provedor

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.

A chave está em
Algoritmo
Formato da assinatura

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.

Decodificar JWT

Quer ler o payload do webhook? Formate numa aba separada. O JSON formatado tem outros bytes e não serve para conferir a assinatura.

Formatar JSON

Precisa só do hash, sem chave? O gerador de hash calcula MD5, SHA-1 e SHA-256 de texto e arquivo.

Gerar hash

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.

ProvedorHeaderO que é assinadoFormato
GitHubX-Hub-Signature-256corposha256=<hex>
StripeStripe-Signaturet.corpot=<ts>,v1=<hex>
ShopifyX-Shopify-Hmac-Sha256corpo<base64>
Mercado Pagox-signatureid:…;request-id:…;ts:…;ts=<ts>,v1=<hex>
SlackX-Slack-Signaturev0:timestamp:corpov0=<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.