Skip to main content

Webhook Verification

Webhook is a static helper for verifying the HMAC-SHA256 signature that Zeridion Flare attaches to every outbound webhook delivery. Always verify the signature before processing an event.

Namespace: Zeridion.Flare · Assembly: Zeridion.Flare.dll

Webhook.Verify

public static bool Verify(
byte[] payload,
string signatureHeader,
string secret,
TimeSpan? tolerance = null)
ParameterTypeDescription
payloadbyte[]The raw request body bytes. Must be the exact bytes the server signed — do not deserialize and re-serialize the JSON first.
signatureHeaderstringThe full value of the X-Zeridion-Signature header (t=<unix_timestamp>,v1=<hex_digest>).
secretstringThe subscription secret returned once when the webhook was created or rotated.
toleranceTimeSpan?Optional replay protection: reject signatures whose timestamp differs from the current time by more than this duration. Recommended: TimeSpan.FromMinutes(5). Default: no timestamp check.

Returns true only when a signature digest matches (constant-time comparison) and, if tolerance is set, the timestamp is within the window. Returns false for malformed headers or empty inputs; throws ArgumentNullException only when payload is null.

Usage

using Zeridion.Flare;

app.MapPost("/hooks/zeridion", async (HttpRequest request) =>
{
using var ms = new MemoryStream();
await request.Body.CopyToAsync(ms);
byte[] rawBody = ms.ToArray();

string header = request.Headers["X-Zeridion-Signature"].ToString();

if (!Webhook.Verify(rawBody, header, webhookSecret, tolerance: TimeSpan.FromMinutes(5)))
return Results.BadRequest();

// Safe to process the event.
return Results.Ok();
});

Secret rotation

During the 24-hour rotation grace window the signature header carries two v1= digests — one per secret. Verify checks every v1= value and accepts if any match, so a receiver that always verifies against the latest secret keeps working through a rotation with no code change.

See also