Webhooks¶
The Webhooks module provides a standard interface for validating inbound webhook signatures from external providers. It includes HmacSignature utilities for timing-safe HMAC computation and per-provider validator implementations.
Quick Start¶
using Deepstaging.Webhooks;
// Validate a webhook in a handler
[Webhook<SlackWebhookValidator>]
[HttpPost("/webhooks/slack")]
public static Eff<AppRuntime, Unit> HandleSlackEvent(SlackEvent evt) =>
// Webhook signature is validated before this handler runs
from _ in processEvent(evt)
select unit;
Features¶
| Feature | Description |
|---|---|
IWebhookValidator |
Core interface — Validate(WebhookValidationContext) |
WebhookValidationContext |
Request signature, raw body, headers, and provider metadata |
HmacSignature |
Static utility — ComputeSha256Hex, ComputeSha256Base64, ComputeSha1Base64, TimeSafeEquals |
[Webhook<T>] |
Attribute on dispatch handlers — auto-validates before handler runs |
| Provider validators | Slack, Stripe, Twilio, Bandwidth, SNS |
Core Interface¶
HmacSignature Utilities¶
All HMAC computations use timing-safe comparison to prevent timing attacks:
// Compute HMAC-SHA256 hex
var signature = HmacSignature.ComputeSha256Hex(secret, payload);
// Compute HMAC-SHA256 base64
var signature = HmacSignature.ComputeSha256Base64(secret, payload);
// Compute HMAC-SHA1 base64 (for legacy providers)
var signature = HmacSignature.ComputeSha1Base64(secret, payload);
// Timing-safe comparison
var isValid = HmacSignature.TimeSafeEquals(expected, actual);
Provider Validators¶
| Provider | Validator Class | Signature Scheme |
|---|---|---|
| Slack | SlackWebhookValidator |
HMAC-SHA256 with v0= prefix and timestamp |
| Stripe | StripeWebhookValidator |
HMAC-SHA256 with t= timestamp |
| Twilio | TwilioWebhookValidator |
HMAC-SHA1 base64 of URL + params |
| Bandwidth | BandwidthWebhookValidator |
Basic auth validation |
| Amazon SNS | SnsWebhookValidator |
Certificate-based signature verification |
Implementing a Custom Validator¶
public sealed class MyProviderWebhookValidator(MyProviderConfig config) : IWebhookValidator
{
public bool Validate(WebhookValidationContext context)
{
var expected = HmacSignature.ComputeSha256Hex(
config.WebhookSecret,
context.RawBody);
return HmacSignature.TimeSafeEquals(expected, context.Signature);
}
}
Templating¶
When sending outbound webhooks to third-party consumers, use Scriban templates to define customizable JSON payload formats. This lets consumers configure the shape of webhook payloads without code changes.
// Templates/Webhooks/OrderEvent.scriban-json
{
"event": "{{ event_type }}",
"timestamp": "{{ timestamp | date.to_string "%Y-%m-%dT%H:%M:%SZ" }}",
"data": {
"order_id": "{{ order.id }}",
"status": "{{ order.status }}",
"total": {{ order.total }}
{{- if order.tracking_url }},
"tracking_url": "{{ order.tracking_url }}"
{{- end }}
}
}
For syntax reference and best practices, see Scriban Templating.
Sub-Pages¶
| Page | Description |
|---|---|
| Attributes | [Webhook<T>] attribute, WebhookValidationContext fields, dispatch integration |
Source¶
src/Core/Deepstaging.Runtime/Webhooks/