Search code examples
hashwebhooksslackslack-apihmac

Why the webhook signature sent by slack in the request header is not matching with the calculated webhook signature at our server?


The problem that we are facing is: The webhook signature sent by slack in the request header is not matching with the calculated webhook signature at our server, but only for the first request that is made when the Zervise app for Slack is opened and any of the tab is accessed. From the next requests the signatures are matching.

Our back-end server supports both the following type of request body that slack is using:

  • application/json
  • application/x-www-form-urlencoded

Following is the back-end code for checking the slack webhook signature:

const slack = (req, res, next) => {
  if (
    !req.headers['x-slack-request-timestamp'] ||
    Math.abs(
      Math.floor(new Date().getTime() / 1000) -
        +req.headers['x-slack-request-timestamp']
    ) > 300
  )
    return res.status(400).send('Request too old!');

  const baseStr = `v0:${
    req.headers['x-slack-request-timestamp']
  }:${qs.stringify(req.body, {
    format: 'RFC1738',
  })}`;
  const receivedSignature = req.headers['x-slack-signature'];
  const expectedSignature = `v0=${crypto
    .createHmac('sha256', env.SLACK_SIGNING_SECRET)
    .update(baseStr, 'utf8')
    .digest('hex')}`;

  if (expectedSignature !== receivedSignature) {
    console.log('WEBHOOK SIGNATURE MISMATCH');
    return res.status(400).send('Error: Signature mismatch security error');
  }

  console.log('WEBHOOK VERIFIED');
  next();
};

The screenshots of the console logs are added below. Each screenshot includes the request headers, the received signature from slack (receivedSignature) and the calculated signature at our server (expectedSignature). I have also tried to use the raw body of request to calculate the signature, but it is still not matching from the first request only.

Following are the screenshot list:

  1. Screenshot of the console logs for the first request where the signatures are not matching: app opened and the first request from slack
  2. Screenshot of the console logs for the subsequent request where the signatures are matching: subsequent requests from slack

Solution

  • The issue is resolved. I needed to use the request body in raw form instead of the encoded formats. Doing that solved the signature mismatch problem. Please check the following article written by me, where I have described the process in detail: Verifying requests from Slack - The CORRECT method for Node.js