Security
We support signing Webhook's payloads and we force using HTTPS
for your webhook URLs.
HTTPS/SLS
We only accept endpoints in HTTPS
in both sandbox and production. Your endpoint must have a valid certificate and self-signed certificates are not accepted.
Webhook Signature
All our Webhooks are sent with a signature to validate their authenticity. You should compare the signature we sent in X-Yousign-Signature-256
header with the signature you recreate. To recreate the signature you have to:
- Retrieve webhook associated secret key through the app by clicking "Copy secret key" in the right menu,
- Compute an
HMAC SHA-256
hash of the entire Webhook's payload as binary, using the Webhook Subscription secret_key as a key, - Add "sha256=" at the beginning of the binary hash.
Make sure you compute the hash from a raw version of the webhook payload.
Examples
// /!\ getallheaders() function does not work on all web servers.
$headers = getallheaders();
$expectedSignature = $headers['X-Yousign-Signature-256'] ?? null;
$payload = file_get_contents('php://input'); // This is an example, you should get the content from an HTTP request
$secret = 'SECRET_KEY_OF_YOUR_WEBHOOK';
$digest = hash_hmac('sha256', $payload, $secret);
$computedSignature = "sha256=" . $digest;
$doSignaturesMatch = hash_equals($expectedSignature, $computedSignature);
import hmac
import hashlib
SECRET = "SECRET_KEY_OF_YOUR_WEBHOOK"
signature = "SIGNATURE_FROM_REQUEST_HEADERS_RECEIVED"
data = "DATA_FROM_REQUEST_PAYLOAD"
digest = hmac.new(SECRET.encode("utf-8"), data.encode("utf-8"), hashlib.sha256).hexdigest()
computed_signature = f"sha256={digest}"
matches = hmac.compare_digest(signature, computed_signature)
const express = require("express");
const crypto = require("crypto");
const https = require("https");
const app = express();
const secret = 'YOUR_WEBHOOK_SECRET_KEY';
const port = 3000;
// SSL Certification
const options = {
key: 'PRIVATE_KEY',
cert: 'CERTIFICATE',
};
/**
* If you are not using Express, you need to find a way to get the raw request body and
* encoding it.
* You can for example, use the `raw-body` middleware https://www.npmjs.com/package/raw-body
*/
app.use(
express.json({
verify: (req, res, buf, encoding) => {
if (buf && buf.length) {
req.rawBody = buf.toString(encoding || "utf-8");
}
},
})
)
app.post('/hook', (req, res) => {
const signature = Buffer.from(req.get('X-Yousign-Signature-256') || '', 'utf8');
const hmac = crypto.createHmac('sha256', secret);
const computedSignature = Buffer.from(`${'sha256' + '='}${hmac.update(req.rawBody).digest('hex')}`, 'utf8');
const isSignatureMatch = crypto.timingSafeEqual(signature, computedSignature)
})
https.createServer(options, app).listen(port);
public class Main {
public static void main(String[] args) {
String payload = "..."
String signature = "sha256=0af379c7522c538c3f26a4f4399e55d7a1ed928420735a4538c73232587be9d6";
String SECRET = "2977fd4b627d28c6e54501b4e8a667ae";
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
sha256_HMAC.init(secret_key);
byte[] hash = sha256_HMAC.doFinal(payload.getBytes());
StringBuilder result = new StringBuilder();
for (byte b : hash) {
result.append(String.format("%02x", b));
}
String computedSignature = "sha256=" + result.toString();
boolean matches = signature.equals(computedSignature);
}
}
Domain validation
You will find below the range of IPs that we use to send our Webhooks for you to authorize them if needed:
CIDR 5.39.7.128/28 (from IP 5.39.7.128 to IP 5.39.7.143)
52.143.162.31
51.103.81.166
Updated 1 day ago