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

# Webhook Signature Verification

> Verify webhook events you received to ensure they are authentic and not tampered with.

## Why?

Due to the nature of webhooks, attackers can impersonate services by simply sending a fake webhook to an endpoint. Consider this: it's merely an HTTP POST from an unknown source. This poses a potential security risk for many applications, or at the very least, a source of issues.

In order to prevent this, ChatBrick signs each webhook and its metadata with a unique key for each endpoint. This signature can then be used to verify that the webhook indeed comes from ChatBrick, and it should only be processed if this is the case.

Another potential security risk is what's known as replay attacks. A [replay attack](https://en.wikipedia.org/wiki/Replay_attack) occurs when an attacker intercepts a valid payload (including the signature) and re-transmits it to your endpoint. This payload will pass signature validation and will therefore be acted upon.

To mitigate this attack, ChatBrick includes a timestamp for when the webhook attempt occurred. Our libraries automatically reject webhooks with a timestamp that is more than five minutes away (past or future) from the current time. This requires your server's clock to be synchronized and accurate, and it's recommended that you use [NTP](https://en.wikipedia.org/wiki/Network_Time_Protocol) to achieve this.

For additional information about webhook security and vulnerabilities, please refer to [Svix's webhook security documentation](https://docs.svix.com/security).

## Verifying using Libraries

To more easily verify incoming webhook events, you can use libraries provided by our partner, Svix.

<Warning>
  You need to use the raw request body when verifying webhooks, as the cryptographic signature is sensitive to even the slightest changes.

  You should watch out for frameworks that parse the request as JSON and then stringify it because this too will break the signature verification.
</Warning>

<Tabs>
  <Tab title="JavaScript">
    First install the library using your package manager of choice:

    ```bash Install the Package theme={null}
    # NPM
    npm install svix
    # PNPM
    pnpm install svix
    # Yarn
    yarn add svix
    ```

    Then, verify the webhook event using the code below. The `payload` is the raw (string) body of the request, and the `headers` are the headers passed in the request.

    ```javascript theme={null}
    import { Webhook } from "svix";

    // The secret is unique to each endpoint
    // Yoy can retrieve it from the ChatBrick dashboard
    const secret = "whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw";

    // These were all sent from the ChatBrick server
    const headers = {
      "svix-id": "msg_p5jXN8AQM9LWM0D4loKWxJek",
      "svix-timestamp": "1614265330",
      "svix-signature": "v1,g0hM9SsE+OTPJTGt/tmIKtSyZlE3uFJELVlNIOLJ1OE=",
    };

    // The payload is the raw JSON string sent by ChatBrick
    // Please note that the payload should be the raw request body, not a parsed JSON object.
    const payload = '{"test": 2432232314}';

    const wh = new Webhook(secret);

    // Throws on error, returns the verified content on success
    const payload = wh.verify(payload, headers);
    ```
  </Tab>

  <Tab title="C#">
    ```powershell theme={null}
    dotnet add package Svix
    ```

    ```dotnet theme={null}
    using Svix;
    using System.Net;

    // These were all sent from the ChatBrick server
    var headers = new WebHeaderCollection();
    headers.Set("svix-id", "msg_p5jXN8AQM9LWM0D4loKWxJek");
    headers.Set("svix-timestamp", "1614265330");
    headers.Set("svix-signature", "v1,g0hM9SsE+OTPJTGt/tmIKtSyZlE3uFJELVlNIOLJ1OE=");

    // The payload is the raw JSON string sent by ChatBrick
    // Please note that the payload should be the raw request body, not a parsed JSON object.
    var payload = "{\"test\": 2432232314}";

    // The secret is unique to each endpoint
    // Yoy can retrieve it from the ChatBrick dashboard
    var wh = new Webhook("whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw/Je4ZJEGP1QFb");

    // Throws on error
    wh.Verify(payload, headers);
    ```
  </Tab>

  <Tab title="Java">
    <CodeGroup>
      ```gradle Gradle theme={null}
      implementation "com.svix:svix:0.x.y"
      ```

      ```xml Maven theme={null}
      <dependency>
        <groupId>com.svix</groupId>
        <artifactId>svix</artifactId>
        <version>0.x.y</version>
      </dependency>
      ```
    </CodeGroup>

    ```java theme={null}
    import com.svix.Webhook;

    // The secret is unique to each endpoint
    // Yoy can retrieve it from the ChatBrick dashboard
    String secret = "whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw";

    // These were all sent from the ChatBrick server
    HashMap<String, List<String>> headerMap = new HashMap<String, List<String>>();
    headerMap.put("svix-id", Arrays.asList("msg_p5jXN8AQM9LWM0D4loKWxJek"));
    headerMap.put("svix-timestamp", Arrays.asList("1614265330"));
    headerMap.put("svix-signature", Arrays.asList("v1,g0hM9SsE+OTPJTGt/tmIKtSyZlE3uFJELVlNIOLJ1OE="));
    HttpHeaders headers = HttpHeaders.of(headerMap, BiPredicate<String, String>)

    // The payload is the raw JSON string sent by ChatBrick
    // Please note that the payload should be the raw request body, not a parsed JSON object.
    String payload = "{\"test\": 2432232314}";

    Webhook webhook = new Webhook(secret);

    webhook.verify(payload, headers)
    // throws WebhookVerificationError exception on failure.
    ```
  </Tab>

  <Tab title="PHP">
    ```bash theme={null}
    composer require svix/svix
    ```

    ```php theme={null}
    // import using composers autoload
    require_once('vendor/autoload.php');
    // or manually
    require_once('/path/to/svix/php/init.php');

    // These were all sent from the ChatBrick server
    $header = array(
      'svix-id'  => 'msg_p5jXN8AQM9LWM0D4loKWxJek',
      'svix-timestamp' => '1614265330',
      'svix-signature' => 'v1,g0hM9SsE+OTPJTGt/tmIKtSyZlE3uFJELVlNIOLJ1OE=',
    );

    // The payload is the raw JSON string sent by ChatBrick
    // Please note that the payload should be the raw request body, not a parsed JSON object.
    $payload = '{"test": 2432232314}';

    // The secret is unique to each endpoint
    // Yoy can retrieve it from the ChatBrick dashboard
    $wh = new \Svix\Webhook('whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw');

    // Throws on error, returns the verified content on success
    $json = $wh->verify($payload, $header);
    ```
  </Tab>

  <Tab title="Python">
    To use the Svix library in this language, you can follow the instructions provided in the [Svix documentation](https://docs.svix.com/receiving/verifying-payloads/how).
  </Tab>

  <Tab title="Ruby">
    To use the Svix library in this language, you can follow the instructions provided in the [Svix documentation](https://docs.svix.com/receiving/verifying-payloads/how).
  </Tab>

  <Tab title="Go">
    To use the Svix library in this language, you can follow the instructions provided in the [Svix documentation](https://docs.svix.com/receiving/verifying-payloads/how).
  </Tab>

  <Tab title="Kotlin">
    To use the Svix library in this language, you can follow the instructions provided in the [Svix documentation](https://docs.svix.com/receiving/verifying-payloads/how).
  </Tab>

  <Tab title="Rust">
    To use the Svix library in this language, you can follow the instructions provided in the [Svix documentation](https://docs.svix.com/receiving/verifying-payloads/how).
  </Tab>
</Tabs>

## Verifying Manually

If your language is not supported by the Svix library, you can verify the signature manually.

Please refer to Svix's [Verifying Webhooks Manually documentation](https://docs.svix.com/receiving/verifying-payloads/how-manual) for more information.
