Skip to main content
Back to all posts

DevOps Best Practices: How to Share API Keys Securely

โ€ขSnapSend Team

As developers, we handle secrets every day: AWS access keys, database passwords, Stripe tokens, third-party API keys. And yet the way we hand them to each other is often shockingly casual. A key that took thirty seconds to generate can sit in a chat log for years, valid the entire time. This post is the practical workflow for sharing API keys without leaving a trail.

Why API keys need special handling

An API key is a bearer credential. Whoever holds the string is the account, no second factor, no login prompt, no "was that really you?" check. That makes keys fundamentally different from a password protected by MFA:

  • No second factor. A leaked password often still needs an OTP. A leaked key usually needs nothing.
  • Broad scope by default. Most providers hand you a key with far more permission than the task requires.
  • Long-lived. Keys rarely expire on their own. A key you shared in 2024 probably still works today.
  • Machine-readable. Automated scanners crawl public repos, paste sites, and chat exports specifically hunting for sk_live_, AKIA, and ghp_ prefixes.

The takeaway: a key is valid from the moment it leaks until the moment someone rotates it. Your job when sharing one is to shrink that window to as close to zero as possible.

Where keys actually leak

Almost none of these are dramatic hacks. They're workflow habits:

  • Slack and Teams DMs. Chat is retained, searchable, and indexed. If an account is compromised years later, a search for key or token surfaces everything. (More on this in sending API keys over Slack.)
  • Email. It sits in two mailboxes and every backup of both, forever.
  • Committed .env files. Git never forgets. A key removed in a later commit is still in the history.
  • Tickets and screenshots. A key pasted into a Jira comment or captured in a screen-share ends up in systems you don't control.

Step 1: Scope the key before you share it

The single highest-leverage habit is least privilege. Before you share anything, create a dedicated key that can do only what the recipient needs:

  • AWS: issue a scoped IAM key with a narrow policy, not your root or admin credentials.
  • Stripe: use a restricted key limited to the specific resources, instead of the full secret key.
  • GitHub: generate a fine-grained personal access token scoped to one repo, read-only where possible.
  • Add an IP allowlist and an expiry date wherever the provider supports it.

Scoping doesn't prevent a leak, it caps the blast radius. A read-only key limited to one bucket is a nuisance if it leaks; an admin key is a company-ending event.

Step 2: Share it once, then let it self-destruct

The right transport for a key is an ephemeral, one-time-use, end-to-end encrypted link, not a message that lingers. This is where a tool like SnapSend fits. The key is encrypted in your browser with AES-256-GCM, and the decryption key lives in the URL #fragment, which is never sent to the server. The backend only ever stores ciphertext it cannot read, a zero-knowledge design where the server never holds the means to decrypt.

The workflow:

  1. Generate the scoped key from Step 1.
  2. Paste it into the text-sharing tool.
  3. Set it to read once and give it a short expiry (an hour or a day, not a week).
  4. Send the resulting link over Slack or email.

Sending the link over Slack is fine, that's the point. Once your teammate opens it, the ciphertext is deleted and the link is dead. Slack's history now holds a URL that decrypts to nothing. This is the burn-on-read property, and it gives you a useful canary: if your colleague reports the link is already expired and you never opened it, someone else did, and you should rotate the key immediately.

For a service-account JSON file or a .pem too large to paste as text, use the encrypted file tool instead, which applies the same one-time, zero-knowledge model to the whole file.

Step 3: Rotate after the handoff

Any key that has been transferred human-to-human should be considered rotatable. Ephemeral sharing shrinks the exposure window during transit, but the recipient now has a live credential on their machine. For high-value production keys:

  • Put a rotation reminder on the calendar, or automate it.
  • Rotate immediately when someone leaves the project or the company. Don't wait, this is a core item on any offboarding checklist.
  • Prefer providers that support short-lived, auto-expiring credentials so rotation is the default, not a chore.

Requesting a key from someone else

The reverse problem is just as common: a vendor or client needs to send you a key. Don't make them figure out a secure method, hand them a pre-encrypted inbox. The secure receive flow generates a one-time upload link so they can send you a secret without an account and without it landing in your email. You get the same zero-knowledge guarantees on the inbound path.

Common mistakes

  • One master key for everyone. If you can't revoke one person's access without breaking everyone's, you don't have a sharing strategy, you have a liability.
  • "I'll just email it for now." "For now" becomes forever. That mailbox is backed up in a dozen places.
  • Sharing via a live doc. A Google Doc or Notion page with a key in it stays readable to anyone with the link, indefinitely.
  • Skipping rotation after a leak scare. If you're not sure whether a key was exposed, rotate it. Rotation is cheap; a breach is not.
  • Reusing a personal token as a shared service credential. Machine access should use machine credentials, not a human's personal token.

Quick checklist

  • [ ] Created a dedicated, least-privilege key for this share
  • [ ] Set an expiry and IP allowlist where supported
  • [ ] Sent it as a one-time, encrypted link, never raw in chat
  • [ ] Link set to read-once with a short expiry
  • [ ] Rotation scheduled for high-value keys
  • [ ] Old or unused keys revoked

FAQ

Is it really safe to send the one-time link over Slack? Yes. The link only works once, and the secret is deleted the moment it's read. After that, the link in your chat history is inert.

How short should the expiry be? Short enough to cover the handoff and no longer. An hour is plenty when you're both online; a day is a reasonable maximum for async.

What if the recipient says the link already expired? Treat it as a possible interception. Rotate the key, then send a fresh link. The dead-link canary is a feature, not a bug.

Where do keys belong long-term? Not in a share link at all, those are for transit. At rest, keys live in a secret manager (Vault, AWS Secrets Manager, Doppler) and each engineer's password manager. Share links are for transit only.


Security isn't only about the encryption algorithm; it's about workflow hygiene. Scope the key, share it once, let it self-destruct, then rotate. When you next need to hand a teammate a token, paste it into the text-sharing tool and send a link that dies on first read, no account, no trail.