How to store API keys safely (without committing them)
“Safely” has two parts: (1) they never enter Git history, and (2) they are not trivially copied to every backup, chat window, and screenshot by accident. This article is a practical playbook — vendor dashboards change, but the order of operations stays the same.
1. Golden rules
- If it touched Git remotely, rotate — cleaning history is necessary but not sufficient. See I accidentally committed an API key.
- Separate test vs live — Stripe
sk_test_vssk_live_, AWS dev account vs prod account, etc. - Minimum scope — read-only tokens where possible; IP allowlists where the vendor supports them.
- Never embed server keys in frontend bundles — frontend leak guide.
2. Storage tiers (where keys should live)
| Layer | Store API keys here? | Notes |
|---|---|---|
| Git repo | No (only .env.example placeholders) | Practical Git guide |
| CI (GitHub Actions, GitLab, etc.) | Yes — in masked secrets | Prefer OIDC to clouds when possible |
| Production runtime | Yes — platform secret manager | AWS Secrets Manager, GCP Secret Manager, K8s Secret, etc. |
| Developer laptop | Yes — vault or strict gitignored .env | Prefer Keychain-oriented workflows |
3. Git guardrails that actually catch mistakes
.gitignore
.env
.env.*
!.env.example
Local scan before push
gitleaks detect --source . -v
Install from gitleaks. Wire into pre-commit — same patterns as keep secrets out of Git.
GitHub push protection
Enable secret scanning and push protection for supported patterns. Official: About secret scanning.
4. The safest pattern on macOS for day-to-day dev
Canonical copy lives in a local-first vault (PassStore):
- Encrypted at rest (AES-256-GCM; Argon2id key wrapping — Security).
- Sensitive items can use Apple Keychain Services.
- Workspaces mirror repos or products so you do not paste the wrong key.
Ephemeral use: copy into a shell session or a gitignored .env you treat as cache, not the system of record.
5. Worked example: new third-party API
- In the vendor UI, create a key named
acme-api-dev-yourname(auditable naming). - Paste into vault entry
stripe_secret_key_dev(or your team convention from organize API keys). - Add
STRIPE_SECRET_KEY=to.env.examplewith a fake value. - Locally: set real value only in vault → copy to
.envorexport. - CI: store in
STRIPE_SECRET_KEYsecret; inject at runtime — never echo.
6. When you must share a key with a teammate
Avoid Slack and email. Prefer:
- Per-person dev keys from the vendor.
- Internal secret store your company already pays for.
- Break-glass procedures with expiry.
Longer discussion: share environment variables safely with your team.
7. Rotation triggers (do not wait for “annual review”)
Rotate immediately when:
- A key appeared in Git, logs, or tickets.
- A teammate with access left the org (for shared keys).
- You suspect malware or lost device.
Step-by-step: rotate API keys safely.
8. Soft CTA
Download PassStore for macOS if you want API keys off Slack and out of Git, with a workflow built for developers. For comparison shopping, see best secret management tools for developers in 2026.