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

# Overview

> Learn how to secure your webhooks.

To verify that events were sent by Orum and not by a third party, Orum digitally signs our webhooks. This prevents data modification by third parties in the middle of the webhook transfer and ensures that the webhooks you receive have come from Orum.

Orum will send a `Signature` header on each webhook request we make to your server. The signature is made up of the following 2 components, which are then encrypted with an Orum-managed private key:

* The webhook request body

* The `created_at` timestamp in the request body

The two components are concatenated into the following formula for the digital signature: SHA256(request.body + plaintext timestamp of `created_at`). We utilize a standardized signing library with PKCS1 v1.5 padding, the signature is base64 encoded.

Using the public key that is returned to by making a GET request to the `webhooks/secret` [endpoint](/api-reference/webhooks/get-webhook-secret), you can verify the message has not been altered and that it is in fact coming from Orum.

## Configure and Retrieve Your Public Key

You can set up webhook signing keys using either Monitor or API endpoints:

### Option 1: Using Monitor (Automatic Generation)

Monitor automatically handles key generation when you retrieve your secret.

For detailed instructions, see the [Webhook Management Guide](/guides/monitor/webhooks/webhook-management).

### Option 2: Using API Endpoints

For programmatic key management:

<Steps>
  <Step title="Initialize your public key">
    Orum manages a public-private RSA-2048 key pair that allows you to decrypt your digital signature. To initialize your public key, make a POST request to the `webhooks/secret` [endpoint](/api-reference/webhooks/post-webhook-secret).
  </Step>

  <Step title="Retrieve your public key">
    Once the key is initialized, you may retrieve it at any time by making a GET request to the `webhooks/secret` [endpoint](/api-reference/webhooks/get-webhook-secret).
  </Step>
</Steps>

##

## How to Validate the Signature

To verify the digital signature, follow these steps:

<Steps>
  <Step title="Recreate the unencrypted plaintext digital signature">
    Take a SHA256 hash of the concatenated string of the following information:

    1. The webhook request body

    2. Plaintext timestamp of `created_at` field in the request body
  </Step>

  <Step title="Decrypt the digital signature with your public key">
    This can be retrieved by making a GET request to `webhooks/secret` [endpoint](/api-reference/webhooks/get-webhook-secret)
  </Step>

  <Step title="Verify that the decrypted digital signature from Orum and your recreated unencrypted plaintext digital signature match" />
</Steps>

### Code Examples

<CodeGroup>
  ```bash bash theme={null}
  import base64
  from Crypto.PublicKey import RSA
  from Crypto.Hash import SHA256
  from Crypto.Signature import pkcs1_15

  # Python3 with pycryptodome

  message_plus_created_at = req.body + created_at
  orumSignature = req.headers['Signature']

  encoded = message_plus_created_at.encode()
  result = SHA256.new(encoded)

  try:
      key = RSA.import_key(publicKeyString)
      pkcs1_15.new(key).verify(
          result, base64.b64decode(orumSignature)) # Will return an error if the signature does not match
      print("verified!")
  except:
      print("Oops")
  ```
</CodeGroup>

<CodeGroup>
  ```bash bash theme={null}
  // Node.js:
  const messagePlusCreatedAt = JSON.stringify(req.body) + req.body.created_at
  const signature = req.headers.signature;
  const verify = crypto.createVerify('RSA-SHA256');
  verify.update(messagePlusCreatedAt);
  const isValid = verify.verify(publicKey, signature,'base64'); // boolean value
  ```
</CodeGroup>

<CodeGroup>
  ```bash bash theme={null}
  import java.nio.charset.StandardCharsets;
  import java.security.*;
  import java.security.spec.X509EncodedKeySpec;
  import java.util.Base64;
  import org.json.JSONObject;

  public class Main {
          public static void main(String[] args) throws Exception {
              String publicKeyStr = // public key returned by GET /webhooks/secret endpoint
              String body = // request body
              String sign = // Signature from request header
              JSONObject json = new JSONObject(body);
              String messagePlusCreatedAt = body + json.getString("created_at");

              byte[] publicKeyBytes = Base64.getDecoder().decode(publicKeyStr);
              X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeyBytes);
              KeyFactory keyFactory = KeyFactory.getInstance("RSA");
              PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
              byte[] digest = messagePlusCreatedAt.getBytes(StandardCharsets.UTF_8);
              Signature sig = Signature.getInstance("SHA256withRSA");
              sig.initVerify(publicKey);
              sig.update(digest);
              boolean verifySign = sig.verify(Base64.getDecoder().decode(sign));
              System.out.println(verifySign);
          }
  }
  ```
</CodeGroup>
