Skip to content

Webhooks Security

Secure your webhook endpoints to verify requests from Islamic Open Finance™.

All webhook requests include a signature header:

X-IOF-Signature: t=1234567890,v1=abc123...
  1. Extract timestamp and signature from header
  2. Prepare the signed payload
  3. Compute expected signature
  4. Compare signatures
import crypto from "crypto";
function verifyWebhook(
payload: string,
signature: string,
secret: string,
): boolean {
const [timestamp, sig] = signature
.split(",")
.map((part) => part.split("=")[1]);
const signedPayload = `${timestamp}.${payload}`;
const expectedSig = crypto
.createHmac("sha256", secret)
.update(signedPayload)
.digest("hex");
return crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expectedSig));
}
import { IslamicOpenFinance } from "@iof/sdk";
const iof = new IslamicOpenFinance({ apiKey: process.env.IOF_API_KEY });
app.post("/webhooks", (req, res) => {
const isValid = iof.webhooks.verify(
req.body,
req.headers["x-iof-signature"],
process.env.WEBHOOK_SECRET,
);
if (!isValid) {
return res.status(401).send("Invalid signature");
}
// Process webhook
});

Reject requests older than 5 minutes:

const timestamp = parseInt(parts[0].split("=")[1]);
const now = Math.floor(Date.now() / 1000);
if (now - timestamp > 300) {
throw new Error("Request too old");
}

Webhook requests come from these IP ranges:

52.20.0.0/16
54.160.0.0/16
  1. Always verify signatures
  2. Use HTTPS endpoints only
  3. Respond quickly (< 30s)
  4. Implement idempotency
  5. Log all webhook events