Aller à la documentation
Java

Vérifier les webhooks

Vérifiez la signature d'une livraison avant de vous fier à ce qu'elle dit.

Vérifier une livraison

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 lit l'en-tête X-OpenEmail-Signature, vérifie son HMAC sur l'horodatage et le corps en temps constant, et renvoie l'événement sous forme de Map<String, Object>. Le secret est celui que client.webhooks().create a renvoyé.

Les en-têtes sont une map dont les noms ont n'importe quelle casse et dont chaque valeur est un texte ou une liste de textes : exchange.getRequestHeaders() et les HttpHeaders de Spring conviennent donc tels quels. La valeur de l'en-tête elle-même fonctionne aussi.

Passez le corps brut, exactement tel qu'il est arrivé. Un corps analysé puis réencodé ne correspond plus à sa signature.

Livraisons anciennes

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());}

Une livraison de plus de cinq minutes est refusée : une requête interceptée ne peut donc pas être rejouée plus tard. Une Duration en dernier argument change ces cinq minutes, et Duration.ZERO accepte une livraison de n'importe quel âge.

  • Un en-tête manquant ou mal formé, une signature qui ne correspond pas et une livraison trop ancienne lèvent tous une WebhookSignatureException.
  • Après la rotation d'un secret, une livraison peut porter plusieurs signatures, et il suffit que l'une d'elles corresponde.
  • Répondez vite avec un statut 2xx. Une livraison qui reçoit une autre réponse est retentée plus tard.