DEV Community

Vincent Voyer
Vincent Voyer

Posted on

How to verify signatures from Slack incoming requests with Next.js

Hi there, this is a short blog post for anyone looking to handle Slack incoming requests with Next.js.

When creating a Slack application that will interact with your web application, Slack will call you back on some actions like:

Here's an example Slack postMessage call:

import { WebClient } from "@slack/web-api";
const web = new WebClient(token);
web.postMessage({
  channel: "#general",
  // fallback for mobile and email notifications:
  text: "Please visit <https://google.com>",
  blocks: [{
    type: "section",
    text: {
      type: "mrkdwn",
      text: "Please visit https://google.com"
    }
  }, {
    type: "actions",
    elements: [{
      type: "button",
      text: {
        type: "plain_text",
        text: "google",
      },
      url: `https://google.com`,
      action_id: "go_to_google_button",
    }],
  }]
});
Enter fullscreen mode Exit fullscreen mode

If you do this, you'll get this result:

Screenshot of a Slack message with a button.

And if you click on the "google" button, it will open Google in your browser. Pretty cool way to link from Slack to your web app for example.

But, that's not the end of the story. If you only do this then Slack will complain because a button, even if it only open a new url, is still an interactive element from Slack point of view.

So Slack will try to call the URL defined in your application "Interactivity & Shortcuts" Slack settings.

And it will fail because you've not defined a route for that.

Now to solve that, if you're using Next.js, you have to define a route as follow:

// pages/api/slackInteractiveEndpoint.js

import { createMessageAdapter } from "@slack/interactive-messages";

// you can find this secret in your app "Basic information" tab
const slackInteractions = createMessageAdapter(slackSigningSecret); 

slackInteractions.action(
  { type: "button", actionId: "go_to_google_button" },
  // no need to reply, it's just a button to a url
  () => {},
);

export default slackInteractions.requestListener();

export const config = {
  api: {
    bodyParser: false,
    externalResolver: true,
  },
};
Enter fullscreen mode Exit fullscreen mode

Then add this route in your Slack application "Interactivity & Shortcuts" tab. Test one message, click on the button and .. voilà!

Because the Slack SDK is responsible for parsing the body and replying to the request, we tell Next.js to let it go via:

  • bodyParser: false
  • externalResolver: true

Hope this helped you! Post a comment otherwise :)

Top comments (0)