# Webhook Signature Verification

### 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:

```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.
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

* Use a testing tool like <https://www.devglan.com/online-tools/hmac-sha256-online> to quickly produce expected hashes and compare to the signature sent by Pakk using the previously suggested webhook testing tool.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.pakk.io/data-and-integrations/webhooks/webhook-signature-verification.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
