# Storing tokens, secrets and installations safely

*Slack Developer Study Guide · Design for Security · Last updated October 21, 2026 · https://www.certifyforce.com/study-guide/slack-developer/design-for-security/storing-tokens-secrets-and-installations-safely*

Where each Slack credential belongs (environment variables in development, a secrets manager in production, a database keyed by workspace and user for customer tokens, the OS keychain for local tools), how a Bolt installation store saves and fetches workspace and org-wide installs, how to keep rotating tokens consistent across servers, and when to delete tokens.

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

**Official exam objective:**

> Store and retrieve data and tokens safely.

## What the exam expects

- Keep tokens, signing secrets and client secrets out of source code and repositories: `.env` files for development, a secrets manager for production.
- Keep the client secret on a server you control, never in desktop, mobile or client-side code; use the OS keychain for tokens on a user's machine.
- Implement a Bolt installation store (`storeInstallation`, `fetchInstallation`, `deleteInstallation`) on a persistent database, keyed by team ID or, for org-wide installs, enterprise ID.
- Store each token linked to its workspace and user, and look it up from the incoming request's IDs.
- With token rotation, persist the new refresh token every time and run one refresh job per installation into a shared store.
- Delete tokens on `tokens_revoked` and `app_uninstalled`, including backups; store only what you need and never show or log tokens.

Key terms: **secrets manager** (a service that injects secrets at build or run time, such as AWS Secrets Manager or HashiCorp Vault); **installation store** (Bolt's handlers that persist and look up installations); **installation object** (what Bolt passes to `storeInstallation` after an install); **`installQuery`** (the IDs Bolt passes to fetch or delete an installation); **refresh token** (single-use credential for getting a new access token).

## Key facts

| Fact | Detail | Source |
|---|---|---|
| Development secrets | `.env` file, with `.env` in `.gitignore` | [Security best practices](https://docs.slack.dev/concepts/security/) |
| Production secrets | Secrets manager (GitHub Actions Secrets, AWS Secrets Manager, HashiCorp Vault) | [Security best practices](https://docs.slack.dev/concepts/security/) |
| Client secret | Never in email, native apps, client-side JavaScript or public repos | [Security best practices](https://docs.slack.dev/concepts/security/) |
| Local tools | System keychain; no plaintext tokens on disk | [Security best practices](https://docs.slack.dev/concepts/security/) |
| `FileInstallationStore` | Development and testing only | [Bolt OAuth](https://tools.slack.dev/bolt-js/concepts/authenticating-oauth) |
| Installation store handlers | `storeInstallation`, `fetchInstallation`, `deleteInstallation` | [Bolt OAuth](https://tools.slack.dev/bolt-js/concepts/authenticating-oauth) |
| Org-wide install key | `enterprise.id` when `isEnterpriseInstall` is true; `team` is undefined | [Bolt OAuth](https://tools.slack.dev/bolt-js/concepts/authenticating-oauth) |
| Refresh tokens | Single-use; persist the new one from every refresh | [Using token rotation](https://docs.slack.dev/authentication/using-token-rotation/) |
| Repeated refreshes | Limit of 2 active tokens; oldest extra revoked | [Using token rotation](https://docs.slack.dev/authentication/using-token-rotation/) |
| `tokens_revoked` payload | User IDs per token type, not token strings | [tokens_revoked](https://docs.slack.dev/reference/events/tokens_revoked) |
| Event order | `tokens_revoked` may arrive after `app_uninstalled` | [app_uninstalled](https://docs.slack.dev/reference/events/app_uninstalled) |
| Deleting tokens | From all production systems and backups | [Security best practices](https://docs.slack.dev/concepts/security/) |

## Check yourself

- Why must a desktop app never contain the client secret?
- When does a Bolt installation store need the enterprise ID as its key?
- Why does reusing the refresh token saved at install fail on the second refresh?
- What does the `tokens_revoked` event contain?

## Sources

- [Security best practices](https://docs.slack.dev/concepts/security/)
- [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/)
- [tokens_revoked event](https://docs.slack.dev/reference/events/tokens_revoked)
- [app_uninstalled event](https://docs.slack.dev/reference/events/app_uninstalled)
- [Installing via OAuth authorization code flow](https://docs.slack.dev/authentication/installing-with-oauth/)
- [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 11 linked practice questions, and unlimited timed mock exams are included with the Slack Developer pack (USD $19): https://www.certifyforce.com/practice-exams
