JITSU-100: webhook destination optional request signing (HMAC / Ed25519)#1392
Conversation
There was a problem hiding this comment.
Reviewed the webhook-signing change set in libs/destination-functions plus the console destination schema wiring and lockfile updates. I focused on request-signing correctness (payload/timestamp signing, header emission, and no-secret behavior) and didn’t find actionable bugs or regressions in this PR diff.
ac66b36 to
07899cd
Compare
07899cd to
7312ab2
Compare
There was a problem hiding this comment.
Reviewed the webhook signing changes in destination function runtime, destination schema metadata, and the new tests. The HMAC implementation and test coverage for stream mode look solid. I left one correctness concern around how signing is communicated/configured for batch mode, since the current execution path still bypasses the new signing headers there.
7312ab2 to
c759249
Compare
There was a problem hiding this comment.
Reviewed the webhook signing implementation across runtime logic, destination schema, console field wiring, and the added tests. I found one actionable correctness/security gap: signing silently turns off when a signing method is selected but the corresponding key material is missing.
c759249 to
79cbe28
Compare
There was a problem hiding this comment.
Reviewed the 8-file diff for webhook signing support and related console form wiring/tests. I focused on runtime correctness and security behavior in , destination schema/UI changes, and the new signing tests.\n\nI did not find additional actionable issues beyond the already-open discussion threads on this PR.
There was a problem hiding this comment.
Reviewed the 8-file diff for webhook signing support and related console form wiring/tests. I focused on runtime correctness and security behavior in webhook-destination.ts, destination schema/UI changes, and the new signing tests.
I did not find additional actionable issues beyond the already-open discussion threads on this PR.
Add optional signing to the webhook destination via a `signatureMethod` choice: none (default), hmac, or ed25519. - hmac: symmetric HMAC-SHA256 with a shared secret (Stripe/GitHub style). - ed25519: asymmetric signature — Jitsu signs with a private key, the receiver verifies with the public key and cannot forge messages. The private key is accepted as PEM or a bare base64 body. Both emit the hex signature in a configurable header (default `Jitsu-Signature`, validated as a legal HTTP header name). Replay protection is on by default: the unix-seconds timestamp is folded into the signed payload (`<timestamp>.<body>`) and sent in a companion `<header>-Timestamp` header; it can be turned off to sign the body only. Misconfigurations fail as NoRetryError instead of retrying forever: a malformed key/secret, or a method selected with no key. Signing covers stream-mode delivery only; batch mode (Bulker) is unsigned, warned in both the destination form and the connection editor. The console form shows only the fields relevant to the selected method, and gains a reusable `placeholder` prop for config fields.
79cbe28 to
3b0593d
Compare
There was a problem hiding this comment.
Reviewed the webhook signing implementation across destination runtime, schema metadata, and console UI wiring. I also checked the updated tests and existing resolved review threads; I didn’t find additional correctness, security, or user-visible regression issues in the current diff.
|
🚀 |
Closes
JITSU-100What
Adds optional request signing to the Webhook destination so receivers can
verify events came from Jitsu and weren't tampered with. Signing is off by
default, so existing webhook destinations are unchanged.
Config —
signatureMethodnone(default) — no signing.hmac— symmetric HMAC-SHA256 with a shared secret (Stripe/GitHub style).Simple, but whoever can verify can also forge — use only for endpoints you
fully trust.
ed25519— asymmetric signature. Jitsu signs with a private key; thereceiver verifies with the public key and cannot forge messages. Preferred
when many or untrusted endpoints receive the webhook. The private key is
accepted as PEM or a bare base64 body (whitespace-tolerant).
The console form shows only the fields relevant to the chosen method
(
signatureSecretfor hmac, private key for ed25519, header + replay options forboth).
Header scheme (same for both methods)
Jitsu-Signature— hex signature (HMAC-SHA256 digest, or Ed25519 signature)Jitsu-Signature-Timestamp— unix seconds (when replay protection is on)Signed content is
<timestamp>.<body>with replay protection (default) or theraw body without it. Signing uses Node's
crypto(createHmac/sign), bothavailable in the function runtime.
Receiver verification (defaults: replay protection on)
HMAC
Ed25519 (endpoint holds only the public key)
Verify against the raw request body (before JSON parsing).
Tests
webhook-destination.test.tsuses MSW to intercept the realfetch(nomocked fetch, matching #1388) and asserts the outbound signature:
HMAC with/without timestamp, Ed25519 verified against a generated public key, the
bare-base64 key form with surrounding whitespace, and that a malformed key fails
as a non-retryable error.
Robustness
NoRetryError(dropped, not retried forever)instead of being wrapped as a retryable error.
Notes / follow-ups
mode only enqueues to Bulker — the actual POST happens in Bulker (Go), which
has no signing. The signing UI now warns that signing applies to stream mode
only. Signing batches would be a separate Bulker (Go) change.
shows the public key" UX is a possible fast-follow.
Deferred (low severity, reviewed and intentionally not fixed here)
createPrivateKey) per event — could memoizeby key string if it ever shows on a hot path.
signatureHeadercan still collide with a user-configured header orContent-Type(signature wins); the value is now validated as a legal headername but not checked against other header names.
(hidden, unused) — secret-retention hygiene.
/api/destinationscatalog endpoint doesn't surface the newplaceholderfield (non-functional; the editor uses the client-side path).
header.split(":"), which truncatesvalues containing
:and keeps leading whitespace.