ether-webhook provee firma HMAC y verificación de webhooks con WebhookSigner, WebhookVerifier y un cliente de entrega WebhookDeliveryClient.
Instalación
<dependency>
<groupId>dev.rafex.ether.webhook</groupId>
<artifactId>ether-webhook</artifactId>
<version>8.0.0-SNAPSHOT</version>
</dependency>
WebhookPayload — construir el payload
WebhookPayload payload = WebhookPayload.ofJson(
UUID.randomUUID().toString(),
"user.created",
new UserCreatedEvent(42L, "Alice", "alice@example.com")
);
WebhookPayload textPayload = WebhookPayload.ofText(
UUID.randomUUID().toString(),
"order.shipped",
"Pedido #123 enviado el 2025-06-01"
);
payload = payload
.withHeader("X-Api-Version", "2")
.withHeader("X-Source", "my-app");
String deliveryId = payload.deliveryId();
String eventType = payload.eventType();
Instant occurredAt = payload.occurredAt();
byte[] body = payload.body();
Map<String,List<String>> headers = payload.headers();
HttpRequestSpec req = payload.toRequest(URI.create("https://listener.example.com/webhook"));
WebhookSigner — firmar payloads (HMAC)
byte[] secret = System.getenv("WEBHOOK_SECRET").getBytes(StandardCharsets.UTF_8);
WebhookSigner signer = new HmacWebhookSignerVerifier(secret);
WebhookSignature signature = signer.sign(payload);
String sigValue = signature.value();
String sigHeader = signature.headerName();
WebhookVerifier — verificar firmas recibidas
byte[] secret = System.getenv("WEBHOOK_SECRET").getBytes(StandardCharsets.UTF_8);
WebhookVerifier verifier = new HmacWebhookSignerVerifier(secret);
WebhookPayload received = buildPayloadFromRequest(httpExchange);
WebhookSignature incomingSig = WebhookSignature.of(
exchange.headerFirst("X-Hub-Signature-256")
);
WebhookVerificationResult result = verifier.verify(received, incomingSig);
if (!result.isValid()) {
exchange.noContent(401);
return true;
}
processEvent(received.eventType(), received.body());
exchange.noContent(200);
return true;
WebhookDeliveryClient — enviar webhooks
WebhookDeliveryClient deliveryClient = new WebhookDeliveryClient(
httpClient,
signer
);
deliveryClient.deliver(
URI.create("https://customer.example.com/webhooks"),
payload
);
WebhookHeaders — cabeceras estándar
WebhookHeaders.DELIVERY_ID
WebhookHeaders.EVENT_TYPE
WebhookHeaders.SIGNATURE_SHA256
WebhookHeaders.TIMESTAMP
Patrón productor de webhooks con ether-di
public class AppContainer {
private final Lazy<WebhookSigner> signer = new Lazy<>(() ->
new HmacWebhookSignerVerifier(
config.get().require("webhook.secret").getBytes(StandardCharsets.UTF_8)
));
private final Lazy<WebhookDeliveryClient> webhookClient = new Lazy<>(() ->
new WebhookDeliveryClient(httpClient.get(), signer.get()));
public WebhookDeliveryClient webhookClient() { return webhookClient.get(); }
}
Patrón receptor de webhooks (endpoint HTTP)
public class WebhookReceiverResource implements HttpResource {
private final WebhookVerifier verifier;
private final EventProcessor processor;
@Override
public boolean post(HttpExchange x) {
WebhookPayload payload = WebhookPayload.from(x);
WebhookSignature sig = WebhookSignature.of(x.headerFirst("X-Hub-Signature-256"));
WebhookVerificationResult r = verifier.verify(payload, sig);
if (!r.isValid()) { x.noContent(401); return true; }
processor.process(payload.eventType(), payload.body());
x.noContent(200);
return true;
}
@Override
public Set<String> supportedMethods() { return Set.of("POST"); }
}
Más información