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

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