# 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 %}
