# Webhook Signature Verification

# Overview

Webhook is a mechanism for receiving real-time event notifications, used to transmit data to your application. When we send a webhook notification, a signature is included in the header to ensure the integrity of the notification and the authenticity of its source.

## Signature Header

In every event notification, the **`Signature`** in the header contains a timestamp and a signature.

The timestamp is prefixed with `t=`, and the signature is prefixed with `v1`.

*Example:*

```JavaScript
Signature:t=1492774577,v1=6fdfb9c357542b8ee07277f5fca2c6f728bae2dce9be2f91412f4de922c1bae4
```

## Webhook Secret

For every event notification, a unique secret key is generated: `whsec_`.

Before verifying the signature, you need to retrieve your webhook secret, which can be extracted from the `secret` field within the webhook object.

![image.png](https://api.apifox.cn/api/v1/projects/1296482/resources/398011/image-preview)

# Verifying Your Signature

By comparing the **signature in the header** with your **locally generated signature**, you can verify whether the signature was issued by us.

Follow the guide below step-by-step to verify your signature.

## Step 1: Extract Timestamp and Signature from the Header

You can split and extract the signature elements using `,` as a delimiter. Then, separate the prefix and value of each element using the `=` sign.

After extraction, the value corresponding to the prefix `t` is the timestamp, and `v1` corresponds to the signature.

*Example:*

```
t=1687845304,v1=6fdfb9c357542b8ee07277f5fca2c6f728bae2dce9be2f91412f4de922c1bae4
```

## Step 2: **Prepare** the **`signed_payload`** String

The `signed_payload` string is created by concatenating the following:

- The timestamp (as a string)
- The character `.`
- The actual JSON payload (i.e., the request body)

You can refer to the format below to prepare the **`signed_payload`** string:

*`1687845304`**+**`.`**+**`JSON payload`*

```JSON
1687845304.{
  "id": "evt_1NNUrjL6kclEVx6Mb1x5dKJ3",
  "object": "event",
  "api_version": "2022-11-15",
  "created": 1687845303,
  "data": {
    "object": {
      "id": "prod_O9oUVgsSaordCT",
      "object": "product",
      "active": true,
      "livemode": true,
      "name": "test",
      "type": "service",
  "livemode": true,
  "pending_webhooks": 1,
  "type": "product.created"
}
```

## Step 3: Generate the **Local Signature**

Calculate the HMAC hash using the SHA256 hash function.

- You can obtain your webhook secret from the `webhook.secret` field in the webhook object. This `whsec_` string will serve as the **Key** for generating the HMAC hash.
- Use the `signed_payload` string prepared in Step 2 as the **Message** for generating the HMAC hash.

By combining the Key + Message in the SHA256 hash function, you will obtain a string of HMAC characters, which is your local signature.

*Example:*

```Java
 public static void main(String[] args) {
        String webhookSecret = "whsec_261V2mfsXt1BsOjJbHaQOxnTzhWZKrUE";
        String timestamp = "1687845304";
        String requestBody = "{\"id\":\"evt_1NNUrjL6kclEVx6Mb1x5dKJ3\",\"object\":\"event\",\"api_version\":\"2022-11-15\",\"created\":1687845303,\"data\":{\"object\":{\"id\":\"prod_O9oUVgsSaordCT\",\"object\":\"product\",\"active\":true,\"livemode\":true,\"name\":\"test\",\"type\":\"service\",\"livemode\":true,\"pending_webhooks\":1,\"type\":\"product.created\"}";
        String signedPayload = timestamp+"."+requestBody;
        String sha256 = hmacSha256(webhookSecret,signedPayload);
        String signature = "t="+timestamp+",v1="+sha256;
    }

    /**
     * HMAC-SHA256 Signature Algorithm
     */
    public static String hmacSha256(String secret, String message) {
        String res;
        try {
            Mac mac = Mac.getInstance("HmacSHA256");
            SecretKey secretKey = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
            mac.init(secretKey);
            byte[] hash = mac.doFinal(message.getBytes());
            res = Hex.encodeHexString(hash);
        } catch (Exception e) {
            return null;
        }
        return res;
    }
```

## Step 4: Compare Local Signature and **Signature in Header**

Compare the **local signature** with the **signature in the header**. Perform an equality check. Additionally, calculate the difference between the timestamp corresponding to `created` in the webhook object and the timestamp in the **signature in the header**, then determine if this difference falls within your acceptable tolerance range.

To prevent timing attacks, use a constant-time string comparison method when comparing the **local signature** with the received **signature in the header**.
