JavaScript Package
Use cside's JavaScript package to verify webhook signatures and handle notification events with full TypeScript support.
Installing the package
Install the cside webhooks package:
npm i @cside.dev/webhooks
Using the package
constructEvent(body, signature, secret) verifies the x-cside-signature
header against the raw request body and returns the parsed event. It throws
Error("Invalid signature") when the signature does not match, so wrap the
call in a try/catch and respond with 400 in that case.
import { constructEvent } from "@cside.dev/webhooks";
const rawBody = req.rawBody; // The raw request body as a string; how you get it depends on your HTTP framework
const signature = req.headers["x-cside-signature"]; // Sent with every cside webhook request
const event = await constructEvent(
rawBody,
signature,
process.env.CSIDE_WEBHOOK_SECRET, // The secret you configured on the webhook destination
);
switch (event.event) {
case "alert.created": {
const alert = event.data;
console.log({
domainId: event.domain_id,
target: alert.target,
action: alert.action,
});
}
}
The package also exports verifyHmac(body, signature, secret) if you only need
the signature check and want to parse the body yourself.
The Event and AlertCreatedObject types shipped in @cside.dev/webhooks
describe an older payload. The engine sends timestamp (not sent_at), plus
top-level domain and trigger_type, and the data object uses target_type
and carries ruleset_* and vuln_* fields. The package also only types
alert.created, not the digest events. Refer to the payload
reference for the
fields that are actually sent, and cast or validate the returned event
accordingly.
Examples
import Fastify from 'fastify';
import { constructEvent } from "@cside.dev/webhooks";
const fastify = Fastify({ logger: true });
await fastify.register(import('@fastify/raw-body'), {
field: 'rawBody',
global: false,
routes: ['/webhook']
});
fastify.post('/webhook', {
config: { rawBody: true }
}, async (request, reply) => {
const signature = request.headers['x-cside-signature'];
const webhookEvent = await constructEvent(
request.rawBody,
signature,
process.env.CSIDE_WEBHOOK_SECRET!,
);
switch (webhookEvent.event) {
case "alert.created": {
const alert = webhookEvent.data;
console.log({
domainId: webhookEvent.domain_id,
target: alert.target,
action: alert.action,
});
}
}
});import { createKaitoHandler, KaitoError } from "@kaito-http/core";
import { constructEvent } from "@cside.dev/webhooks";
const app = router()
.get("/", async ({ ctx }) => {
return {
uptime: ctx.uptime,
time_now: Date.now(),
};
})
.post("/", async ({ ctx }) => {
const signature = ctx.req.headers.get("x-cside-signature");
if (!signature) {
throw new KaitoError(400, "Missing signature");
}
const rawBody = await ctx.req.text();
const webhookEvent = await constructEvent(
rawBody,
signature,
process.env.CSIDE_WEBHOOK_SECRET!,
);
switch (webhookEvent.event) {
case "alert.created": {
const alert = webhookEvent.data;
console.log({
domainId: webhookEvent.domain_id,
target: alert.target,
action: alert.action,
});
}
}
return {
message: "OK!",
};
});Thanks for your feedback!