Verifying the signature

Set a signing secret on a webhook output and every request carries:

HeaderMeaning
X-Obserae-Signaturesha256=<hex>, an HMAC-SHA256 over "<timestamp>.<rawBody>".
X-Obserae-TimestampUnix seconds, and part of the signed material — so a captured request cannot be replayed later.
X-Obserae-DeliveryUnique per delivery. Deduplicate on it.
X-Obserae-Eventalert.fired / alert.resolved / alert.acknowledged / test. Route without parsing the body.
X-Obserae-Schemaobserae.alert/2.
X-Obserae-InstanceWhich instance sent it.
User-Agentobserae/<version>.

Verify the raw body, before any JSON parsing. Re-serialising changes the bytes and the signature will not match.

Python

import hashlib, hmac, time

def verify(secret: str, headers, raw_body: bytes, max_age: int = 300) -> bool:
    ts = headers.get("X-Obserae-Timestamp", "")
    sig = headers.get("X-Obserae-Signature", "")
    if not ts.isdigit() or abs(time.time() - int(ts)) > max_age:
        return False                      # too old: a replayed capture
    mac = hmac.new(secret.encode(), (ts + ".").encode() + raw_body, hashlib.sha256)
    return hmac.compare_digest("sha256=" + mac.hexdigest(), sig)

Go

func verify(secret string, h http.Header, rawBody []byte, maxAge time.Duration) bool {
	ts := h.Get("X-Obserae-Timestamp")
	sent, err := strconv.ParseInt(ts, 10, 64)
	if err != nil {
		return false
	}
	if d := time.Since(time.Unix(sent, 0)); d > maxAge || d < -maxAge {
		return false // too old (or too far in the future): a replayed capture
	}
	mac := hmac.New(sha256.New, []byte(secret))
	mac.Write([]byte(ts + "."))
	mac.Write(rawBody)
	want := "sha256=" + hex.EncodeToString(mac.Sum(nil))
	return hmac.Equal([]byte(want), []byte(h.Get("X-Obserae-Signature")))
}

Both use a constant-time comparison: a plain == leaks, one byte at a time, how close a forged signature is.

These two snippets are not written from the specification — they are run, in obserae’s own test suite, against a real signed v2 delivery produced by the daemon (TestDocumentedVerifiersAcceptARealDelivery). If they ever stopped accepting one, the build would fail.