Skip to content
cascadehook.

ToolsFree tool

Slack request signature verifier

Check an X-Slack-Signature header for slash commands, interactivity, and Events API requests, and see why verification fails. Nothing you paste leaves your browser.

Paste request headers

Paste the headers from a log, a request inspector, or curl -v, as Name: value lines or JSON. The matching fields below are filled in.

Signature your code computed (optional)

If your code rejects a request that verifies here, print the signature it computes for this request and paste it. The tool finds which mistake produces that value.

Runs entirely in your browser with Web Crypto. Nothing you paste is sent anywhere or saved.

The result shows up here

Paste your app's signing secret, the two X-Slack headers, and the raw body from a request, then verify. To see how it works first, use Try an example.

What gets signed

HMAC-SHA256(secret, "v0:" + timestamp + ":" + body)

The body was decoded or parsed first

Slash commands and interactive components arrive as application/x-www-form-urlencoded, and Slack signs those raw bytes with their percent-escapes. Once a framework parses the form into fields, the signed bytes are gone. In Flask, call request.get_data() before reading request.form; in Express, use express.raw({ type: "*/*" }) on the route.

The interactivity payload was taken out of the form

Interactive requests send payload= with the JSON URL-encoded inside it. Verify the whole form body first, then read and parse the payload field.

The base string is wrong

Slack signs v0:timestamp:body, joined with colons, using the X-Slack-Request-Timestamp value exactly as sent. Leaving out v0:, joining with periods, or using your own clock's time all produce a different signature.

The wrong secret

Use the Signing Secret from your app's Basic Information page. The Verification Token on the same page is a different, deprecated value, and bot or user tokens (xoxb-, xoxp-) aren't signing secrets at all. Regenerating the secret stops the old one from working.

The request is too old

Reject requests whose timestamp is more than five minutes from your clock, to block replays. A signature that verifies here but fails in your app may just be a request captured earlier. Keep your clock synced with NTP.

Something already read the body

Bolt checks the signature for you when you give it the signing secret. If you add your own check after Bolt or another middleware has consumed the body, it hashes something other than the raw request and fails even for genuine requests.

Sending webhooks from your own product? Cascadehook signs every delivery with Standard Webhooks, retries failures for up to 72 hours, and keeps every attempt for replay. Create a project or try the Standard Webhooks verifier.

Slack is a trademark of Slack Technologies, LLC. Cascadehook isn't affiliated with or endorsed by Slack.