> ## Documentation Index
> Fetch the complete documentation index at: https://dub.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Verify postback requests

> Learn how to verify postback requests to ensure they're coming from Dub.

With signature verification, you can determine if the postback came from Dub, and has not been tampered with in transit.

All postbacks are delivered with a `Dub-Signature` header. Dub generates this header using a secret key that only you and Dub know.

An example header looks like this:

```
Dub-Signature: c9ed6a2abf93f59d761eea69908d8de00f4437b5b6d7cd8b9bf5719cbe61bf46
```

## Finding your postback's signing secret

You can find your postback's signing secret when you create the postback or in the postback details page. Use the **Rotate secret** option if you need to generate a new secret.

Make sure to keep this secret safe by only storing it in a secure environment variable (e.g. `DUB_POSTBACK_SECRET`). Do not commit it to git or add it in any client-side code.

## Verifying a postback request

To verify, you can use the secret key to generate your own signature for each postback. If both signatures match then you can be sure that a received event came from Dub.

The steps required are:

1. Get the raw body of the request.
2. Extract the signature from the `Dub-Signature` header.
3. Calculate the HMAC of the raw body using the `SHA-256` hash function and the secret.
4. Compare the calculated `HMAC` with the one sent in the `Dub-Signature` header. If they match, the postback is verified.

Here's an example of how you can verify a postback request in different languages:

<CodeGroup>
  ```javascript Next.js theme={null}
  export const POST = async (req: Request) => {
    const postbackSignature = req.headers.get("Dub-Signature");
    if (!postbackSignature) {
      return new Response("No signature provided.", { status: 401 });
    }

    // Copy this from the postback details page
    const secret = process.env.DUB_POSTBACK_SECRET;
    if (!secret) {
      return new Response("No secret provided.", { status: 401 });
    }

    // Make sure to get the raw body from the request
    const rawBody = await req.text();

    const computedSignature = crypto
      .createHmac("sha256", secret)
      .update(rawBody)
      .digest("hex");

    if (postbackSignature !== computedSignature) {
      return new Response("Invalid signature", { status: 400 });
    }

    // Handle the postback event
    // ...
  };
  ```

  ```python Python theme={null}
  import hmac
  import hashlib

  def postback():
      # Get the signature from the header
      postback_signature = request.headers.get('Dub-Signature')
      if not postback_signature:
          abort(401, 'No signature provided.')

      # Copy this from the postback details page
      secret = os.environ.get('DUB_POSTBACK_SECRET')
      if not secret:
          abort(401, 'No secret provided.')

      # Get the raw body of the request
      raw_body = request.data

      # Calculate the HMAC
      computed_signature = hmac.new(
          secret.encode('utf-8'),
          raw_body,
          hashlib.sha256
      ).hexdigest()

      if postback_signature != computed_signature:
          abort(400, 'Invalid signature')

      # Handle the postback event
      # ...

      return 'OK', 200
  ```

  ```go Go theme={null}

  import (
  	"crypto/hmac"
  	"crypto/sha256"
  	"encoding/hex"
  	"io/ioutil"
  	"net/http"
  	"os"
  )

  func postbackHandler(w http.ResponseWriter, r *http.Request) {
  	// Get the signature from the header
  	postbackSignature := r.Header.Get("Dub-Signature")
  	if postbackSignature == "" {
  		http.Error(w, "No signature provided.", http.StatusUnauthorized)
  		return
  	}

  	// Copy this from the postback details page
  	secret := os.Getenv("DUB_POSTBACK_SECRET")
  	if secret == "" {
  		http.Error(w, "No secret provided.", http.StatusUnauthorized)
  		return
  	}

  	// Read the raw body
  	body, err := ioutil.ReadAll(r.Body)
  	if err != nil {
  		http.Error(w, "Error reading request body", http.StatusInternalServerError)
  		return
  	}

  	// Calculate the HMAC
  	h := hmac.New(sha256.New, []byte(secret))
  	h.Write(body)
  	computedSignature := hex.EncodeToString(h.Sum(nil))

  	if postbackSignature != computedSignature {
  		http.Error(w, "Invalid signature", http.StatusBadRequest)
  		return
  	}

  	// Handle the postback event
  	// ...

  	w.WriteHeader(http.StatusOK)
  	w.Write([]byte("OK"))
  }
  ```
</CodeGroup>

## Why is signature verification important?

Signature verification is a crucial security measure that protects against request forgery and data tampering. Without verification, malicious actors could send fake postback events to your endpoint, potentially triggering unauthorized actions.

The HMAC-SHA256 signature verification process ensures that only Dub can generate valid postback requests and that payloads haven't been modified in transit. This provides both authentication (confirming the sender is Dub) and integrity (ensuring the message hasn't been tampered with).
