The legacy HMAC webhook envelope for receivers using the :legacy or
:dual signing modes.
AshHooks.Legacy.verify/5 validates its signature.
Envelope:
- MAC — HMAC-SHA256 over
"<unix_ts>.<body>", lowercase hex. sign/3→"v1=<hex>"; rotation appends",v1prev=<hex>"under the separately imported previous secret.- header —
x-webhook-signature: t=<unix_ts>,<signature>.
Use :dual to send this envelope alongside Standard Webhooks while receivers
migrate. New integrations should use :standard.
Summary
Functions
Assembles the header value: t=<unix_ts>,<signature>.
The legacy header set: x-webhook-signature under secret (and optional previous).
HMAC-SHA256 over <unix_ts>.<body>, lowercase hex, v1=-prefixed.
Current and previous signatures comma-joined (zero-downtime rotation).
Verifies a legacy header value: parses t=/v1=, checks the replay
window, compares hex digests in constant time.
Functions
Assembles the header value: t=<unix_ts>,<signature>.
@spec headers(binary(), binary() | nil, binary(), integer()) :: %{ required(String.t()) => String.t() }
The legacy header set: x-webhook-signature under secret (and optional previous).
HMAC-SHA256 over <unix_ts>.<body>, lowercase hex, v1=-prefixed.
Current and previous signatures comma-joined (zero-downtime rotation).
@spec verify(binary(), binary(), binary(), integer(), integer()) :: {:ok, %{unix_ts: integer()}} | {:error, :invalid_signature | :stale_timestamp}
Verifies a legacy header value: parses t=/v1=, checks the replay
window, compares hex digests in constant time.
window defaults to 300 seconds, symmetric around now_ts.