Slack API Signing Signature Verification

Any Slack App that interacts with a server via a slash command, events API, or other outbound webhook should verify that the request actually came from the Slack API. The official docs provide a guide, but the process is far from intuitive (hopefully it improves in the future). Currently, developers are required to manually hash the request and verify that matches the signature. The following snippet demonstrates how to handle this process in Node.

Slack Signing Secret Verification in Node

Dependencies

First, install tsscmp… unless you have a better way to perform timing safe string comparison using double hashed message authentication code (HMAC).

command line
npm i tsscmp

Verify the Signature

The code example is based on a Firebase Cloud Function using TypeScript. If you use body-parser with ExpressJS, you need to stringify the body. You can obtain the signing secret from the Slack App admin basic info page. The code below compares this secret to the request body and signature to guarantee that it was sent from Slack and not some random hacker.

file_type_typescript server.ts
import * as crypto from 'crypto';
import * as tsscmp from 'tsscmp';

function legitSlackRequest(req) {
  // Your signing secret
  const slackSigningSecret = 'your-signing-secret';

  // Grab the signature and timestamp from the headers
  const requestSignature = req.headers['x-slack-signature'] as string;
  const requestTimestamp = req.headers['x-slack-request-timestamp'];

  // Create the HMAC
  const hmac = crypto.createHmac('sha256', slackSigningSecret);

  // Update it with the Slack Request
  const [version, hash] = requestSignature.split('=');
  const base = `${version}:${requestTimestamp}:${JSON.stringify(req.body)}`;
  hmac.update(base);

  // Returns true if it matches
  return tsscmp(hash, hmac.digest('hex'));
}

Use it with Express

You can use this function in an Express endpoint or as middleware.

app.post('/my-slash-command', (req, res) => {

    const legit = legitSlackRequest(req);

    if (!legit) { 
        res.status(403).send('Nice try buddy. Slack signature mismatch.');
    }

});

Questions?

Ask questions via GitHub below OR chat on Slack #questions