@pokutuna/express-validate-slack
A express middleware to verify requests from Slack.
Based on Verifying requests from Slack | Slack
Usage
import express from "express";
import verifySlack, { rawBodyKeeper } from "express-validate-slack";
const app = express();
// 1. To keep original request body as `req.rawBody`.
// Almost all middlewares & frameworks replace `req.body`.
// Verifying requests from Slack requires original body.
//
// This middleware first checks req.rawBody,
// and use req.body if rawBody doesn't exist.
app.use(express.json({ verify: rawBodyKeeper }));
// 2. Enable this middleware
app.use(verifySlack("<SLACK_SIGNING_SECRET>"));
// or enable middleware for a route.
// see https://expressjs.com/en/guide/using-middleware.html
app.post(
"/slack/slash-command",
verifySlack("<SLACK_SIGNING_SECRET>"),
(req, res) => {
...
}
);
Appendix
Cloud Functions
This package is designed for Google Cloud Functions.
You don't need to keep req.rawBody
(Step 1 in Usage) when receiving reqeusts on Cloud Functions.
The rawBody property contains the unparsed bytes of the request body.
HTTP Functions | Cloud Functions Documentation | Google Cloud
Next.js
To use this with Next.js in API Routes, do the following.
API Routes: API Middlewares | Next.js
In pages/api/slack.ts
import type { NextApiRequest, NextApiResponse } from "next";
import type express from "express";
import bodyParser from "body-parser";
import validateSlack, { rawBodyKeeper } from "@pokutuna/express-validate-slack";
export const config = {
api: {
bodyParser: false,
},
};
// runMiddleware from Next.js document
// https://nextjs.org/docs/api-routes/api-middlewares#connectexpress-middleware-support
function runMiddleware(req: NextApiRequest, res: NextApiResponse, fn: express.RequestHandler) {
return new Promise((resolve, reject) => {
fn(req, res, (result) => {
if (result instanceof Error) {
return reject(result);
}
return resolve(result);
});
});
}
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
// Run middlewares
await runMiddleware(req, res, bodyParser.json({ verify: rawBodyKeeper }));
await runMiddleware(req, res, validateSlack("<SLACK_SIGNING_SECRET>"));
// Rest of API logic
// e.g. URL Verification https://api.slack.com/events/url_verification
if (req.body.type === "url_verification") {
const { challenge } = req.body;
return res.status(200).json({ challenge });
}
res.status(200).json({/* ... */});
}