Skip to main content
Installing the package
Language

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.

Package types lag the payload

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!",
    };
});
Was this page helpful?