Relay

Signatures

HMAC-SHA256 webhook signing and verification.

Every webhook delivery is signed with HMAC-SHA256 using the endpoint's signing secret.

Signing format

The signed content is "{timestamp}.{payload}". The signature is returned in the format v1=<hex>.

Headers sent with each delivery

HeaderExample
X-Relay-Signaturev1=5257a869...
X-Relay-Timestamp1704067200

Signing

import "github.com/xraph/relay/signature"

sig := signature.Sign(payload, secret, timestamp)
// "v1=5257a869e4c5a2b5..."

Verification

ok := signature.Verify(payload, secret, timestamp, receivedSignature)

Secret format

Secrets are generated with signature.GenerateSecret():

whsec_<64 hex characters>

Format: whsec_ prefix + 32 random bytes encoded as hex (70 characters total).

Receiver-side verification example

func webhookHandler(w http.ResponseWriter, r *http.Request) {
    body, _ := io.ReadAll(r.Body)
    sig := r.Header.Get("X-Relay-Signature")
    ts := r.Header.Get("X-Relay-Timestamp")

    timestamp, _ := strconv.ParseInt(ts, 10, 64)

    if !signature.Verify(body, mySecret, timestamp, sig) {
        http.Error(w, "invalid signature", http.StatusUnauthorized)
        return
    }

    // Process the webhook...
    w.WriteHeader(http.StatusOK)
}

On this page