actions/verify-slack-signature/verify-slack-signature.mjs
import crypto from "crypto"; import slack from "../../slack.app.mjs"; export default { key: "slack-verify-slack-signature", name: "Verify Slack Signature", description: "Verifying requests from Slack, slack signs its requests using a secret that's unique to your app. [See the documentation](https://api.slack.com/authentication/verifying-requests-from-slack)", version: "0.0.17", annotations: { destructiveHint: false, openWorldHint: true, readOnlyHint: true, }, type: "action", props: { slack, slackSigningSecret: { type: "string", label: "Signing Secret", description: "Slack [Signing Secret](https://api.slack.com/authentication/verifying-requests-from-slack#:~:text=Slack%20Signing%20Secret%2C%20available%20in%20the%20app%20admin%20panel%20under%20Basic%20Info.), available in the app admin panel under Basic Info.", secret: true, }, slackSignature: { type: "string", label: "X-Slack-Signature", description: "Slack signature (from X-Slack-Signature header).", }, slackRequestTimestamp: { type: "string", label: "X-Slack-Request-Timestamp", description: "Slack request timestamp (from X-Slack-Request-Timestamp header).", }, requestBody: { type: "any", label: "Request Body", description: "The body of the request to be verified.", }, }, async run({ $ }) { const { slackSignature, slackRequestTimestamp, requestBody, slackSigningSecret, } = this; const requestBodyStr = typeof (requestBody) === "string" ? requestBody : JSON.stringify(requestBody); const sigBaseString = `v0:${slackRequestTimestamp}:${requestBodyStr}`; const sha256Hex = crypto.createHmac("sha256", slackSigningSecret) .update(sigBaseString, "utf8") .digest("hex"); const mySignature = `v0=${sha256Hex}`; if (crypto.timingSafeEqual(Buffer.from(mySignature, "utf8"), Buffer.from(slackSignature, "utf8"))) { $.export("$summary", `Successfully verified the request with "${slackSignature}" signature`); return { success: true, }; } $.export("$summary", "Slack signature mismatch with provided properties, it may be a configuration issue."); return { success: false, }; }, };