Autenticação e validação
Para garantir que a requisição foi enviada pelo TukanoPay e não foi alterada, use o secret configurado no webhook e valide o header X-Webhook-Signature.
Quando o secret está configurado
Se você definiu um secret ao criar/editar o webhook, todas as requisições incluem o header:
X-Webhook-Signature: <hmac-sha256-hex>
A assinatura é o HMAC SHA256 do corpo bruto da requisição (string JSON), usando o secret como chave.
Como validar (exemplo em Node.js)
const crypto = require('crypto');
function validateWebhookSignature(rawBody, signature, secret) {
if (!secret || !signature) return false;
const expected = crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature, 'utf8'),
Buffer.from(expected, 'utf8')
);
}
// No seu handler (ex.: Express)
app.post('/webhooks/tukanopay', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['x-webhook-signature'];
const secret = process.env.TUKANOPAY_WEBHOOK_SECRET;
if (!validateWebhookSignature(req.body.toString(), signature, secret)) {
return res.status(401).json({ error: 'Assinatura inválida' });
}
const payload = JSON.parse(req.body);
// Processar payload...
res.status(200).send('OK');
});
Importante: use o corpo bruto (raw body) da requisição para calcular o HMAC, não o objeto já parseado. Por isso, no Express use express.raw() para essa rota.
Quando o secret não está configurado
Se você não definiu secret, o header X-Webhook-Signature não é enviado. Nesse caso, qualquer um que conheça sua URL pode enviar POSTs para ela. Para produção, recomenda-se sempre usar secret e validar a assinatura.