# Verifying Slack requests and securing transport

*Slack Developer Study Guide · Design for Security · Last updated October 21, 2026 · https://www.certifyforce.com/study-guide/slack-developer/design-for-security/verifying-slack-requests-and-securing-transport*

How an app proves inbound requests came from Slack (signing secret HMAC over v0:timestamp:raw body, five-minute replay window, mutual TLS, Bolt's built-in check) and how it protects outbound traffic and tokens: url_verification over valid TLS, Socket Mode, the Restrict API Token Usage IP list, tokens in headers, HTTPS redirect URLs and unfurl controls against prompt-injection exfiltration.

- Certification: Salesforce Slack Developer
- Exam section: Design for Security
- Study guide: https://www.certifyforce.com/study-guide/slack-developer

**Official exam objective:**

> Identify the steps you could take to make your app communicate securely in Slack.

## What the exam expects

- Verify an inbound request: rebuild `v0:<timestamp>:<raw body>`, HMAC SHA256 it with the signing secret, compare to `X-Slack-Signature`, and reject timestamps more than five minutes off.
- Diagnose broken verification (parsed or re-serialized bodies) and know Bolt does it when given `signingSecret`.
- Choose mutual TLS or Socket Mode when the requirement is "verify at the load balancer" or "no public endpoint".
- Pass the `url_verification` challenge over HTTPS with a valid certificate.
- Limit a leaked token's damage: Restrict API Token Usage (IP list), token rotation, `auth.revoke`; send tokens in headers, never query strings.
- Secure transport and AI output: validate TLS, HTTPS redirect URLs on domains you control, disable unfurls for model-generated links.

Key terms: **signing secret** (app secret Slack uses to sign every request it sends); **`X-Slack-Signature`** (the `v0=` hex HMAC on each request); **replay attack** (resending a captured, validly signed request); **mutual TLS** (your TLS server authenticates Slack's client certificate); **Restrict API Token Usage** (allowed IP list for the app's tokens).

## Key facts

| Fact | Detail | Source |
|---|---|---|
| Basestring | `v0:` + `X-Slack-Request-Timestamp` + `:` + raw body | [Verifying requests](https://docs.slack.dev/authentication/verifying-requests-from-slack/) |
| Signature format | `v0=` + hex HMAC SHA256 digest, keyed with the signing secret | [Verifying requests](https://docs.slack.dev/authentication/verifying-requests-from-slack/) |
| Replay window | Ignore requests more than five minutes from local time | [Verifying requests](https://docs.slack.dev/authentication/verifying-requests-from-slack/) |
| Verification token | Deprecated; replaced by signing secrets | [Verifying requests](https://docs.slack.dev/authentication/verifying-requests-from-slack/) |
| Mutual TLS identity | Accept only `platform-tls-client.slack.com` | [Verifying requests](https://docs.slack.dev/authentication/verifying-requests-from-slack/) |
| `url_verification` | Valid SSL certificate; respond HTTP 200 with `challenge` | [Using HTTP Request URLs](https://docs.slack.dev/apis/events-api/using-http-request-urls) |
| IP allowlist size | Up to 20 entries per Security best practices (SCIM guide says 10); single IPs or CIDR ranges; no IPv6 or local IPs | [Security best practices](https://docs.slack.dev/concepts/security/) |
| Unlisted IP | Web API call rejected with `invalid_auth`; incoming webhooks exempt | [Security best practices](https://docs.slack.dev/concepts/security/) |
| Token transport | Never in a GET query string; Bearer header or POST body | [Security best practices](https://docs.slack.dev/concepts/security/), [Installing with OAuth](https://docs.slack.dev/authentication/installing-with-oauth/) |
| Enterprise OAuth check | After the exchange, compare the `team.info`/`users.info` domain with the customer's expected domain | [Installing with OAuth](https://docs.slack.dev/authentication/installing-with-oauth/) |
| No public endpoint | Socket Mode over a WebSocket from `apps.connections.open` | [Using Socket Mode](https://docs.slack.dev/apis/events-api/using-socket-mode) |

## Check yourself

- Why does Slack include the timestamp in the signed basestring?
- When is Socket Mode the right answer to a security requirement?
- What must an app return to a `url_verification` request?
- Why should an LLM-backed app turn off unfurling for generated links?

## Sources

- [Verifying requests from Slack](https://docs.slack.dev/authentication/verifying-requests-from-slack/)
- [Security best practices](https://docs.slack.dev/concepts/security/)
- [Using HTTP Request URLs](https://docs.slack.dev/apis/events-api/using-http-request-urls)
- [Using the Slack SCIM API](https://docs.slack.dev/admins/scim-api)
- [Using Socket Mode](https://docs.slack.dev/apis/events-api/using-socket-mode)
- [Installing via OAuth authorization code flow](https://docs.slack.dev/authentication/installing-with-oauth/)
- [chat.postMessage method](https://docs.slack.dev/reference/methods/chat.postMessage)
- [Authenticating with OAuth (Bolt for JavaScript)](https://tools.slack.dev/bolt-js/concepts/authenticating-oauth)
- [Using token rotation](https://docs.slack.dev/authentication/using-token-rotation/)
- [Submission guidelines and requirements](https://docs.slack.dev/slack-marketplace/slack-marketplace-app-guidelines-and-requirements/)

## About the full unit

The "Core concepts", "Exam traps" and "Worked scenario" sections of this unit, its 12 linked practice questions, and unlimited timed mock exams are included with the Slack Developer pack (USD $19): https://www.certifyforce.com/practice-exams
