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
| Header | Example |
|---|---|
X-Relay-Signature | v1=5257a869... |
X-Relay-Timestamp | 1704067200 |
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)
}