Saltar para a documentação
Java

Verificar webhooks

Verifique a assinatura de uma entrega antes de confiar no que ela diz.

Verificar uma entrega

WebhookHandler.java
import com.sun.net.httpserver.HttpExchange;import com.sun.net.httpserver.HttpHandler;import java.io.IOException;import java.nio.charset.StandardCharsets;import java.util.Map;import uk.openemail.OpenEmail;import uk.openemail.exception.WebhookSignatureException; public final class WebhookHandler implements HttpHandler {    @Override    public void handle(HttpExchange exchange) throws IOException {        String rawBody = new String(exchange.getRequestBody().readAllBytes(), StandardCharsets.UTF_8);        String secret = System.getenv("OPENEMAIL_WEBHOOK_SECRET");        int status = 204;         try {            Map<String, Object> event = OpenEmail.verifyWebhookSignature(rawBody, exchange.getRequestHeaders(), secret);             System.out.println(event.get("type") + " " + event.get("id"));        } catch (WebhookSignatureException error) {            status = 400;        }         exchange.sendResponseHeaders(status, -1);        exchange.close();    }}

OpenEmail.verifyWebhookSignature lê o cabeçalho X-OpenEmail-Signature, verifica o seu HMAC sobre a marca temporal e o corpo em tempo constante, e devolve o evento como um Map<String, Object>. O segredo é o que client.webhooks().create devolveu.

Os cabeçalhos são um mapa com nomes em qualquer grafia e um texto ou uma lista de textos como valor, por isso exchange.getRequestHeaders() e os HttpHeaders do Spring servem tal como estão. O valor do próprio cabeçalho também funciona.

Passe o corpo em bruto, exatamente como chegou. Um corpo que foi analisado e codificado de novo já não corresponde à sua assinatura.

Entregas antigas

Tolerance.java
String signature = "t=1767225600,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd";Map<String, String> headers = Map.of("X-OpenEmail-Signature", signature); try {    OpenEmail.verifyWebhookSignature("{}", headers, System.getenv("OPENEMAIL_WEBHOOK_SECRET"), Duration.ofMinutes(1));} catch (WebhookSignatureException error) {    System.err.println(error.getMessage());}

Uma entrega com mais de cinco minutos é recusada, por isso um pedido capturado não pode ser repetido mais tarde. Uma Duration como último argumento altera os cinco minutos, e Duration.ZERO aceita uma entrega de qualquer idade.

  • Um cabeçalho em falta ou mal formado, uma assinatura que não corresponde e uma entrega demasiado antiga lançam todos WebhookSignatureException.
  • Depois de um segredo ser rodado, uma entrega pode trazer mais do que uma assinatura, e basta que uma corresponda.
  • Responda depressa com um estado 2xx. Uma entrega que recebe qualquer outra resposta é tentada de novo mais tarde.