Webhook Signature Verification
All webhook requests sent from Pakk are signed. Here's how to verify the authenticity of the incoming request.
How Requests are Signed
Verifying the Signature
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.
func VerifyWebhookSignature(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 signatures
return hmac.Equal([]byte(expectedSignature), []byte(receivedSignature))
}
// WebhookHandler handles incoming webhooks and verifies their signatures.
func WebhookHandler(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 signature
if !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"))
}Tips and Tools
Last updated