Webhooks Security

Learn about our available webhooks protection mechanisms that you can utilise for extra security.

Although Webhooks are a form of server to server communication and typically more resistant to tampering attempts, it’s still the best practice to introduce security measures to validate their authenticity.

We offer multiple different methods that can be introduced as an additional layer of security.

HTTP Authentication

Webhooks can be setup with a username and a password using Basic HTTP Authentication. See the main Webhooks guide for more detail.

Header Signature

📘

Enterprise only

Webhook header signatures are available only on the Enterprise plan.

Each Webhook request contains a special FPJS-Event-Signature HTTP header that is available as an additional validation measure. We strongly suggest adopting this method instead of Basic HTTP Authentication as it doesn't require sharing any kind of sensitive data (username/password).

The header signature is computed from the HTTP body of the webhook along with a symmetric key (a secret) generated during the webhook creation. HMAC with SHA-256 hash function is used the signature method.

Since the secret remains unique to a specific webhook, it's impossible to spoof invalid data without it.

FPJS-Event-Signature Header Structure

The value of the FPJS-Event-Signature header is a comma-separated list of <signatureversion>=<hash> where the signatureversion is the version of the signature and hash is the computed signature hash.

Currently, the only supported version is v1 and the algorithm for v1 is a HMAC SHA-256 of the HTTP raw payload, using the webhook's secret. The secret is generated for each Webhook during its creation (see Setup below).

Setup

1. Get the Key from the Dashboard

When a webhook is created, we assign a unique symmetric key to it and display it once during the creation process. Save this secret for subsequent usage on your backend so that you can compute your HMAC and validate the webhook from the signature.

Webhook Secret Key

Webhook Secret

2. Verify Signature

The HMAC signature we assign to the FPJS-Event-Signature header is calculated from the raw HTTP payload of the request. An example validation code might look like this

import * as crypto from "crypto";
import { Buffer } from 'buffer';

const checkSignature = (signature: string, data: Buffer, secret: string) => {
    return signature === crypto.createHmac('sha256', secret).update(data).digest('hex');
}

const checkHeader = (header: string, data: Buffer, secret: string) => {
    const signatures = header.split(',');
    for (const signature of signatures) {
        const [version, hash] = signature.split('=');
        if (version === 'v1') {
            if (checkSignature(hash, data, secret)) {
                return true;
            }
        }
    }
    return false
}

//valid (allow)
console.log(checkHeader('v1=89e14bbd118da7945e4547c1b9f32fff890dc141a7162df45c1ccb7546a80b58', Buffer.from('payload'), 'secret'))

//invalid (reject)
console.log(checkHeader('v0=89e14bbd118da7945e4547c1b9f32fff890dc141a7162df45c1ccb7546a80b58', Buffer.from('payload'), 'wrongsecret'))
console.log(checkHeader('v1=79e14bbd118da7945e4547c1b9f32fff890dc141a7162df45c1ccb7546a80b58', Buffer.from('payload'), 'wrongsecret'))

Key Rotation

To rotate the webhook key, create another Webhook with the same URL and a distinctive name. Once you rotate the key on the backend and start ingesting the new signature, you can delete the old webhook completely to prevent duplicated information.