Slack Webhook Specs, Events, and Examples
Slack uses outgoing webhooks to notify third-party apps of events such as messages sent, conversations started, files uploaded, and channels archived.
Specifications |
|
Supported Events | |
Security Headers |
|
Documentation | |
SDKs and Sample Code |
Sample Validation
Slack signs the raw request body, which is JSON for Events API callbacks but form-encoded for slash commands and interactivity. Verify before parsing either format.
const crypto = require('crypto')
const express = require('express')
const app = express()
const timeHeader = 'X-Slack-Request-Timestamp'
const sigHeader = 'X-Slack-Signature'
const hashAlgo = 'sha256'
const encode = 'hex'
const hmacSecret = process.env.WEBHOOK_SECRET
// Capture the raw body for any content type
app.post('/slack-webhook', express.raw({ type: '*/*' }), (req, res) => {
//01: Validate replay prevention with 5 minute timeframe (past or future)
const timestamp = req.get(timeHeader)
if (!timestamp || Math.abs(Date.now() - timestamp * 1000) > 5 * 60 * 1000) {
return res.status(403).send('Request expired')
}
//02: Validate signature
const message = `v0:${timestamp}:${req.body.toString('utf8')}`
const digest = Buffer.from("v0=" +
crypto.createHmac(hashAlgo, hmacSecret)
.update(message)
.digest(encode), 'utf8')
const providerSig = Buffer.from(req.get(sigHeader) || '', 'utf8')
if (providerSig.length !== digest.length || !crypto.timingSafeEqual(digest, providerSig)) {
return res.status(401).send('Request unauthorized')
}
//03: Process message
res.json({ message: "Success" })
})