I’m creating a ChatGPT integrated Slack bot for writing feedbacks. When clicking on a modal button in Slack, the bot should open and automatically start a conversation with the user.
I’ve successfully managed to verify Slack events API requests that trigger when a user sends a message to the bot. However, when a bot sends a message, I’m getting the “signature mismatch” error.
The issue with this is that events API doesn’t have the raw body
field in the request (it is always undefined), so I had to use
JSON.stringify(request.body)
instead of rawBody.
This is the verify Slack function that I use:
export function verifySlackRequest(options: SlackRequestVerificationOptions): void {
const requestTimestampSec = options.headers[`x-slack-request-timestamp`];
if (typeof requestTimestampSec !== 'string') {
throw new Error(
`Failed to verify authenticity: x-slack-request-timestamp is not a valid string`,
);
}
const slackSignature = options.headers[`x-slack-signature`];
const parsedTimestamp = parseInt(requestTimestampSec, 10);
if (isNaN(parsedTimestamp)) {
throw new Error(
`Failed to verify authenticity: x-slack-request-timestamp is not a valid number`,
);
}
// Calculate time-dependent values
const nowMs = options.millisecondsNow ?? Date.now();
const requestTimestampMaxDeltaMin = 5;
const fiveMinutesAgoSec = Math.floor(nowMs / 1000) - 60 * requestTimestampMaxDeltaMin;
// 1: Check staleness
if (parsedTimestamp < fiveMinutesAgoSec) {
throw new Error(
`Failed to verify authenticity: x-slack-request-timestamp must differ from system time by no more than ${requestTimestampMaxDeltaMin} minutes or request is stale`,
);
}
const signatureVersion = 'v0';
// Compute signature hash
const basestring = `${signatureVersion}:${requestTimestampSec}:${options.body}`;
const hmac = createHmac('sha256', options.signingSecret).update(basestring);
const computedSignature = `${signatureVersion}=${hmac.digest('hex')}`;
// 2: Compare signatures
if (slackSignature !== computedSignature) {
throw new Error('Failed to verify authenticity: signature mismatch');
}
}
This is the code that calls it:
const verificationOptions: SlackRequestVerificationOptions = {
signingSecret,
body: type === 'event' ? JSON.stringify(request.body): rawBody as string,
headers: {
'x-slack-signature': headers['x-slack-signature'] as string,
'x-slack-request-timestamp': headers['x-slack-request-timestamp'] as string,
},
millisecondsNow: Date.now(),
};
verifySlackRequest(verificationOptions);
This is my request body for user message:
{"token":"MdNsA0AwBwAodBPVKdQMtQX1","team_id":"","context_team_id":"","context_enterprise_id":null,"api_app_id":"","event":{"user":"","type":"message","ts":"1719869314.344809","client_msg_id":"39f1129d-4282-4a96-8205-bc9198ee4653","text":"hi","team":"","blocks":[{"type":"rich_text","block_id":"a8bcU","elements":[{"type":"rich_text_section","elements":[{"type":"text","text":"hi"}]}]}],"channel":"","event_ts":"1719869314.344809","channel_type":"im"},"type":"event_callback","event_id":"Ev07AHEP12MB","event_time":1719869314,"authorizations":[{"enterprise_id":null,"team_id":"","user_id":"","is_bot":true,"is_enterprise_install":false}],"is_ext_shared_channel":false,"event_context":"4-eyJldCI6Im1lc3NhZ2UiLCJ0aWQiOiJUMEExV0s4VTgiLCJhaWQiOiJBMDc5VTVDUFFWOSIsImNpZCI6IkQwNzlEUlBFSEI5In0"}
This is my request body for bot message:
{"token":"MdNsA0AwBwAodBPVKdQMtQX1","team_id":"","context_team_id":"","context_enterprise_id":null,"api_app_id":"","event":{"user":"","type":"message","ts":"1719869365.739839","bot_id":"B079DP0HEHM","app_id":"","text":"Hi! How can I assist you with creating or improving your feedback message today?","team":"","bot_profile":{"id":"B079DP0HEHM","deleted":false,"name":"Feedback Bot","updated":1719523558,"app_id":"A079U5CPQV9","icons":{"image_36":"https://avatars.slack-edge.com/2024-06-27/7341986592933_3d848180c9c004cec526_36.jpg","image_48":"https://avatars.slack-edge.com/2024-06-27/7341986592933_3d848180c9c004cec526_48.jpg","image_72":"https://avatars.slack-edge.com/2024-06-27/7341986592933_3d848180c9c004cec526_72.jpg"},"team_id":""},"blocks":[{"type":"rich_text","block_id":"jdHl","elements":[{"type":"rich_text_section","elements":[{"type":"text","text":"Hi! How can I assist you with creating or improving your feedback message today?"}]}]}],"channel":"D079DRPEHB9","event_ts":"1719869365.739839","channel_type":"im"},"type":"event_callback","event_id":"Ev07AZ25R6U9","event_time":1719869365,"authorizations":[{"enterprise_id":null,"team_id":"","user_id":"","is_bot":true,"is_enterprise_install":false}],"is_ext_shared_channel":false,"event_context":"4-eyJldCI6Im1lc3NhZ2UiLCJ0aWQiOiJUMEExV0s4VTgiLCJhaWQiOiJBMDc5VTVDUFFWOSIsImNpZCI6IkQwNzlEUlBFSEI5In0"}
Any ideas please?