# Validate Deliveries

Once your server is configured to receive payloads, it will listen for any delivery that's sent to the endpoint you configured. To ensure that your server only processes webhook deliveries that were sent by CarbonRegistry and to ensure that the delivery was not tampered with, you should validate the webhook signature before processing the delivery further. This will help you avoid spending server time to process deliveries that are not from CarbonRegistry and will help avoid man-in-the-middle attacks.

To do this, you need to:

1. Create a secret token for a webhook.
2. Store the token securely on your server.
3. Validate incoming webhook payloads against the token, to verify that they are coming from CarbonRegistry and were not tampered with.

### Create a Webhook Secret

Go to the "General" tab of your CarbonRegistry app's dashboard.

There you'll be able to define a webhook secret that CarbonRegistry will use to sign webhook POST requests.

<figure><img src="/files/hAiInyf7RzMkmPVMH1N5" alt=""><figcaption></figcaption></figure>

### Validating Webhook Deliveries

CarbonRegistry will use your secret token to create a hash signature that's sent to you with each payload. The hash signature will appear in each delivery as the value of the `x-icr-signature-256` header. For more information, see "[Webhook events and payloads](/documentation/carbonregistry.com/api/apps/creating-icr-apps/registering-an-icr-app/webhooks/webhook-actions-and-payloads.md)."

In your code that handles webhook deliveries, you should calculate a hash using your secret token. Then, compare the hash that CarbonRegistry sent with the expected hash that you calculated, and ensure that they match.&#x20;

There are a few important things to keep in mind when validating webhook payloads:

* CarbonRegistry uses an HMAC hex digest to compute the hash.
* The hash signature always starts with `sha256=`.
* The hash signature is generated using your webhook's secret token and a base64 encoding of the payload contents, stored in the `signedData` key in the root of the request payload body.
* If your language and server implementation specifies a character encoding, ensure that you handle the payload as UTF-8. Webhook payloads can contain unicode characters.
* Never use a plain `==` operator. Instead consider using a method like [`secure_compare`](https://www.rubydoc.info/gems/rack/Rack%2FUtils:secure_compare) or [`crypto.timingSafeEqual`](https://nodejs.org/api/crypto.html#cryptotimingsafeequala-b), which performs a "constant time" string comparison to help mitigate certain timing attacks against regular equality operators, or regular loops in JIT-optimized languages.

### Testing Webhook Validation

You can use the following `secret` and `payload` values to verify that your implementation is correct:

* `secret`: "turtleSecret"
* `payload`: "It's no secret turtles rock."

If your implementation is correct, the signatures that you generate should match the following signature value:

* x-icr-signature-256: `sha256=622744da2f7b232aec4663a66d7604bd4f867330487c706b58dbac45af3bb104`&#x20;

### Typescript Example

```typescript
require("dotenv").config();
import express, { Request, Response } from "express";
import * as crypto from "crypto";

const app = express();
app.use(express.json());
app.post("/webhook", (req: Request, res: Response) => {
  const signature = req.header("x-icr-signature-256");
  const signedData = req.body.signedData;
  const verified = verify_signature(signature ?? "", signedData ?? "");

  if (!verified) return res.status(403).send("Forbidden");
  res.status(202).send("Accepted");

  console.log("SIGNATURE:", signature);
  console.log("EVENT:", req.body.event);
  console.log("Installation:", req.body.installation);
  console.log("Organization:", req.body.installation.organization);
  console.log("Sender:", req.body.sender);

  const signedDataDecoded = Buffer.from(signedData ?? "", "base64").toString();
  const signedPayload = JSON.parse(signedDataDecoded);
  console.log("Signed Payload:", signedPayload);
});

const verify_signature = (signature: string, signedData: string) => {
  const signatureCheck = crypto
    .createHmac("sha256", process.env.WEBHOOK_SECRET ?? "")
    .update(signedData)
    .digest("hex");
  const trusted = Buffer.from(`sha256=${signatureCheck}`, "ascii");
  const untrusted = Buffer.from(signature, "ascii");
  try {
    return crypto.timingSafeEqual(trusted, untrusted);
  } catch (error) {
    return false;
  }
};

app.listen(4040, () => {
  console.log("Server is listening on port 4040");
});

```

For repository see [here](https://github.com/Mojoflower-garden/webhook-handler/tree/main).

### Signed Payload

If, for security reasons, you only want to use data that has been signed with your defined secret key you can instead of using the payload body decode the signed data like this:

```typescript
  const signedDataDecoded = Buffer.from(signedData ?? "", "base64").toString();
  const signedPayload = JSON.parse(signedDataDecoded);
  console.log("Signed Payload:", signedPayload);
```

The `signedPayload` will match the request body exactly (except perhaps for the ordering of the keys)


---

# 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://documentation.carbonregistry.com/documentation/carbonregistry.com/api/apps/creating-icr-apps/registering-an-icr-app/webhooks/validate-deliveries.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.
