Cloudflare Worker Code
const SLACK_SIGNING_SECRET = "YOUR_APP_SECRET";
const N8N_WEBHOOK_URL = "YOUR_N8N_WEBHOOK_URL";
export default {
async fetch(req, env, ctx) {
const ts = req.headers.get("X-Slack-Request-Timestamp");
const sig = req.headers.get("X-Slack-Signature");
const body = await req.text();
// verify
const base = `v0:${ts}:${body}`;
const key = await crypto.subtle.importKey(
"raw", new TextEncoder().encode(SLACK_SIGNING_SECRET),
{ name: "HMAC", hash: "SHA-256" }, false, ["sign"]
);
const raw = await crypto.subtle.sign("HMAC", key, new TextEncoder().encode(base));
const hex = [...new Uint8Array(raw)].map(b => b.toString(16).padStart(2,"0")).join("");
if (`v0=${hex}` !== sig) return new Response("Bad signature", { status: 401 });
// URL verification (Events API)
if (req.headers.get("Content-Type")?.includes("application/json")) {
const json = JSON.parse(body);
if (json.type === "url_verification") {
return new Response(JSON.stringify({ challenge: json.challenge }), {
headers: { "Content-Type": "application/json" },
});
}
}
// normalize payload
let payload;
if (req.headers.get("Content-Type")?.includes("application/x-www-form-urlencoded")) {
payload = Object.fromEntries(new URLSearchParams(body));
} else {
try { payload = JSON.parse(body); } catch { payload = { raw: body }; }
}
// reliably forward without blocking Slack
ctx.waitUntil(fetch(N8N_WEBHOOK_URL, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload)
}));
return new Response("", { status: 200 });
}
}
AI Agent System Prompt
Generate a joke based on the user message