Quadrata Integration
  • INTRODUCTION
    • Introduction to Quadrata
    • Passport Attributes
  • HOW TO INTEGRATE
    • Quadrata SDK
      • Get Started Quickly
      • Advanced
        • Installation
        • SDK Configuration
        • Onboarding Example
        • Client Libraries
          • Client Configuration
          • Client Lazy Loading
          • Client Eager Loading
          • Client Helper Component
          • Client React Hooks
            • useOnboardStatus
          • Client Examples
            • With Wagmi Connect
            • KYC Only
            • KYB Only
            • All In One
        • API Libraries
          • API Configuration
          • API Service Options
          • API Service Libraries
            • Create Access Token
            • Create Privacy Access Token
            • Fetch Attribute Values
            • Fetch Onboard Status
            • Fetch Passport List
            • Fetch Privacy Data
            • Fetch Privacy Grants
            • Fetch Wallet Screening
            • Revoke Privacy Grants
    • Onboard users
      • Individual Passport Onboarding
        • 1. Installation
        • 2. API Authentication
        • 3. API Onboard Status
        • 4. QuadClient Package
        • 5. Privacy Data Permissions
        • 6. Full Example
      • Business Passport Onboarding
        • 1. Installation
        • 2. API Authentication
        • 3. QuadrataKyb Package
        • 4. Privacy Data Permissions
        • 5. Full Example
      • All-In-One Passport Onboarding
        • 1. Installation
        • 2. API Authentication
        • 3. QuadrataReact Package
        • 4. Full Example
    • Request Privacy Data
      • List of Privacy Data
      • Privacy Data Permissions
      • API Requests
        • How to sign API
          • Full Example
          • Generate ECDSA Key Pair
        • API Get Privacy Permissions
        • API Privacy Access Token
        • API Get Privacy Data
        • API Revoke Permissions
    • Query attributes
      • Via Smart Contract
        • Query a single attribute
        • Query multiple attributes
        • Query Helper
      • Via API
    • On-Chain Wallet Screening
      • How to sign API
        • Full Example
        • Generate ECDSA Key Pair
      • API Get On-Chain AML Score
    • Webhooks
      • Onboarding Webhooks
      • Ongoing Monitoring Webhooks
      • Webhook Request Signature
    • Burn Passports
  • additional information
    • Smart contracts
    • Quadrata Sandbox
    • Passport Issuers
    • Privileged Roles & Ownership
    • Constants
    • Flex Kit Attributes
      • Smart Contract Addresses
Powered by GitBook
On this page
  • Verifying The Request Signature
  • Quadrata Public Signing Keys
  • Code Samples
  1. HOW TO INTEGRATE
  2. Webhooks

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.

The signature message used to sign and verify is the stringified JSON body payload.

Verifying The Request Signature

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

Quadrata Public Signing Keys

-----BEGIN PUBLIC KEY-----
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE1iwh7gCfjdQRo/r82k8ErKiLO+cbPJkY
zqAqrPe0le6vjYY9aTp92ps37mcHzLjitslHeG4f5nSuBXKz8WXuwSyWhUW6EyZb
v/1tUfucvjBRrT7Yks6u6jmpwPmIuaqI
-----END PUBLIC KEY-----
-----BEGIN PUBLIC KEY-----
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEOuY3rbyrujXxVEWq2X70uRa53ySTjwKR
j1ueDjYuzMegLrxIRiCXWMPtrVuqE0FcZ2YmJSiTaoDsq4yYMJw7fxi6nUj/8bzT
4+IxIok9qaEq9IbX6Bo/95vAu5bwO3rf
-----END PUBLIC KEY-----

Code Samples

// 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);
}
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);
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

If using json.dumps to marshal the JSON body payload into a string, be sure to override the separators:

json.dumps(request_body, separators=(',', ':'))

PreviousOngoing Monitoring WebhooksNextBurn Passports

Last updated 1 year ago