# Webhook Request Signature

Each webhook request that Quadrata emits will contain a header signature that an integrating application can use to verify the authenticity of the message.

Request signatures are sent as `Base64 Encoded` `SHA384` strings, in the `X-WEBHOOK-SIGNATURE` request header.

{% hint style="info" %}
The signature message used to sign and verify is the stringified JSON body payload.
{% endhint %}

## Verifying The Request Signature

To verify the request signature, use Quadrata's public signing key for the respective environment.

### Quadrata Public Signing Keys

{% tabs %}
{% tab title="Staging" %}

```
-----BEGIN PUBLIC KEY-----
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE1iwh7gCfjdQRo/r82k8ErKiLO+cbPJkY
zqAqrPe0le6vjYY9aTp92ps37mcHzLjitslHeG4f5nSuBXKz8WXuwSyWhUW6EyZb
v/1tUfucvjBRrT7Yks6u6jmpwPmIuaqI
-----END PUBLIC KEY-----
```

{% endtab %}

{% tab title="Production" %}

```
-----BEGIN PUBLIC KEY-----
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEOuY3rbyrujXxVEWq2X70uRa53ySTjwKR
j1ueDjYuzMegLrxIRiCXWMPtrVuqE0FcZ2YmJSiTaoDsq4yYMJw7fxi6nUj/8bzT
4+IxIok9qaEq9IbX6Bo/95vAu5bwO3rf
-----END PUBLIC KEY-----
```

{% endtab %}
{% endtabs %}

### Code Samples

{% tabs %}
{% tab title="NodeJS: Crypto" %}

```javascript
// NOTE: this is using Quadrata's Staging webhook signing key
const publicKey = `-----BEGIN PUBLIC KEY-----
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE1iwh7gCfjdQRo/r82k8ErKiLO+cbPJkY
zqAqrPe0le6vjYY9aTp92ps37mcHzLjitslHeG4f5nSuBXKz8WXuwSyWhUW6EyZb
v/1tUfucvjBRrT7Yks6u6jmpwPmIuaqI
-----END PUBLIC KEY-----`;

/**
 * Verify a signed message
 * @param {string} message The request body stringified
 * @param {string} signature The base64 encoded signature
 * @returns {boolean}
 */
function verifySignature(message, signature) {
  const signature = Buffer.from(signature, 'base64');

  // create a verifier and verify the signature
  const verifier = crypto.createVerify('sha384');
  verifier.update(message);
  
  return verifier.verify(publicKey, signature);
}
```

{% endtab %}

{% tab title="NodeJS: Express + Crypto" %}

```javascript
const crypto = require('crypto');
const express = require('express');

// NOTE: this is using Quadrata's Staging webhook signing key
const publicKey = `-----BEGIN PUBLIC KEY-----
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE1iwh7gCfjdQRo/r82k8ErKiLO+cbPJkY
zqAqrPe0le6vjYY9aTp92ps37mcHzLjitslHeG4f5nSuBXKz8WXuwSyWhUW6EyZb
v/1tUfucvjBRrT7Yks6u6jmpwPmIuaqI
-----END PUBLIC KEY-----`;

/**
 * Verify a signed message
 * @param {string} message The request body stringified
 * @param {string} signature The base64 encoded signature
 * @returns {boolean}
 */
function verifySignature(message, signature) {
  const signature = Buffer.from(signature, 'base64');

  // create a verifier and verify the signature
  const verifier = crypto.createVerify('sha384');
  verifier.update(message);
  
  return verifier.verify(publicKey, signature);
}

// initialize the express application
const app = express();

// parse JSON request body into req.body
app.use(express.json());

// webhook request handler
app.post('/quadrata-webhook', (req, res) => {
  
  // verify the request has a webhook signature
  if (!('x-webhook-signature' in req.headers) 
      || !req.headers['x-webhook-signature']
  ) {
    return res.status(400).send();
  }
  
  // stringify the request body
  const signatureMessage = JSON.stringify(req.body);
  
  // extract the base64 signature from headers
  const signature = request.headers['x-webhook-signature'];
  
  // verify the signature
  if (!verifySignature(signatureMessage, signature)) {
    return res.status(400).send();
  }
  
  // webhook is valid, flush a successful response
  res.status(200).send();
  
  // process the event on your servers (you implement this)
  processQuadrataWebhook(req.body)
    .catch(console.error);

});

// listen for traffic
const port = process.ENV.port;
const hostname = process.ENV.hostname;
app.listen(port, hostname);
```

{% endtab %}

{% tab title="Python" %}

```python
import base64

from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import ec, utils

# NOTE: using Quadrata's Staging webhook signing key
PUBLIC_KEY_PEM = """-----BEGIN PUBLIC KEY-----
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE1iwh7gCfjdQRo/r82k8ErKiLO+cbPJkY
zqAqrPe0le6vjYY9aTp92ps37mcHzLjitslHeG4f5nSuBXKz8WXuwSyWhUW6EyZb
v/1tUfucvjBRrT7Yks6u6jmpwPmIuaqI
-----END PUBLIC KEY-----"""

def verify_signature(message: str, b64_signature: str) -> bool:
    public_key = serialization.load_pem_public_key(
        PUBLIC_KEY_PEM.encode('utf-8')
    )
    try:
        public_key.verify(
            base64.b64decode(b64_signature),
            message.encode('utf-8'),
            ec.ECDSA(hashes.SHA384()),
        )
        return True
    except:
        return False
```

{% hint style="warning" %}
If using `json.dumps` to marshal the JSON body payload into a string, be sure to override the separators:&#x20;

`json.dumps(request_body, separators=(',', ':'))`
{% endhint %}
{% endtab %}
{% endtabs %}


---

# 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://docs.quadrata.com/integration/how-to-integrate/webhooks/webhook-request-signature.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.
