All webhook requests sent from Pakk are signed. Here's how to verify the authenticity of the incoming request.
How Requests are Signed
Pakk signs all webhook requests by hashing the request body bytes using HMAC-SHA256 with the webhook signing key (which you can find on the Webhook record in the admin panel) and encoding to Base64. The resulting signature is send in the header X-Pakk-Webhook-Signature.
Verifying the Signature
You should implement verification code that performs the same procedure and compares the result against the received signature. Here's an example of what that code would look like in Go:
import ("crypto/hmac""crypto/sha256""encoding/base64""io""net/http")// SharedSecret is the secret key used for signing and verifying webhook requests.// In production, securely retrieve this from a configuration file or environment variable.var SharedSecret ="your-shared-secret"// VerifyWebhookSignature verifies that the request's payload matches the signature in the header.funcVerifyWebhookSignature(payload []byte, receivedSignature string) bool {// Generate the HMAC-SHA256 signature hash := hmac.New(sha256.New, []byte(SharedSecret)) hash.Write(payload) expectedSignature := base64.StdEncoding.EncodeToString(hash.Sum(nil))// Use hmac.Equal to prevent timing attacks when comparing signaturesreturn hmac.Equal([]byte(expectedSignature), []byte(receivedSignature))}// WebhookHandler handles incoming webhooks and verifies their signatures.funcWebhookHandler(w http.ResponseWriter, r *http.Request) {// Extract the signature from the header receivedSignature := r.Header.Get("X-Pakk-Webhook-Signature")if receivedSignature =="" { http.Error(w, "Missing signature header", http.StatusUnauthorized)return }// Read the raw JSON payload from the request body payload, err := io.ReadAll(r.Body)if err !=nil { http.Error(w, "Failed to read request body", http.StatusInternalServerError)return }defer r.Body.Close() // Make sure to close the body when done reading// Verify the signatureif!VerifyWebhookSignature(payload, receivedSignature) { http.Error(w, "Invalid signature", http.StatusUnauthorized)return }// Process the webhook payload as it's been verified successfully w.WriteHeader(http.StatusOK) w.Write([]byte("Webhook received and verified"))}