Skip to content

Developer Security

How to Send API Keys Safely

Scope the key, send it through an expiring encrypted link, confirm it arrived, and rotate on the right triggers. A step-by-step guide with a decision table.

By Updated
First published 6 min read

An API key is a credential, not a message. Depending on the provider it can read customer data, spend money or change infrastructure, and most keys work from anywhere until someone revokes them. Sending one is a small security event: done well, it leaves nothing behind; done casually, it leaves a working key in a chat history for as long as the key lives.

This guide covers the whole handoff: making the key worth less, sending it, and cleaning up afterwards.

The short version

  1. Ask whether the person can get their own key instead.
  2. If not, create a new key for this person and purpose, with the narrowest permissions the provider offers.
  3. Send it through an encrypted link that expires after one read, not as text in chat or email.
  4. Confirm it arrived, and let the link delete itself.
  5. Revoke or rotate the key when the work ends, or straight away if anything looks wrong.

Why chat and email are the wrong place

Providers say this plainly. Stripe's API key documentation lists "don't share keys over email, chat or other unencrypted channels" among its rules for protecting keys. The problem isn't only interception, it's retention. Chat history is searchable and synced to every member's devices, and workspace admins can export it. Email sits in two mailboxes and their backups. A key pasted into any of them stays usable for as long as the key is valid.

Places that feel private often aren't. A GitHub "secret" gist is unlisted, not private: GitHub's documentation on creating gists says secret gists aren't private, and anyone who has or discovers the URL can see them. Tickets, wikis and pull request comments are designed to be kept and searched.

Before you send: make the key worth less

The less a key can do, the less it matters where it ends up.

  • Give people their own keys. Google Cloud's best practices for API keys recommend isolating keys and giving each team member their own key for each application. A personal key can be revoked without breaking anyone else, and usage shows who did what.
  • Restrict permissions. Stripe's restricted API keys (rk_…) let you choose exactly which resources a key can touch, and Stripe recommends them over unrestricted secret keys. Google Cloud keys can be limited to specific APIs and to specific apps, websites or IP addresses.
  • Use test or sandbox keys for development. Someone building locally usually doesn't need a key that can touch production.
  • Prefer short-lived credentials where they exist. AWS's IAM best practices recommend that workloads use temporary credentials through IAM roles, and that people sign in through federation rather than with long-term access keys.
  • Set an expiry or a spending limit if the provider supports one.

How to send an API key, step by step

ProtectedShare's EnvShare was built for exactly this:

  1. Paste the key with a little context, for example STRIPE_KEY=rk_test_… and a line saying which environment it's for. The text is encrypted in your browser with AES-256-GCM before upload.
  2. Choose one read. Choose two only if they'll genuinely open it in two places.
  3. Choose a short expiry: an hour if they're online now, a day at most otherwise.
  4. For production keys, add a password and send it another way: say it on a call, or use a different app from the one carrying the link.
  5. Send the link through your normal channel. The decryption key travels after the #, which browsers don't send to servers (MDN). The server stores ciphertext and deletes it after the last allowed read.
  6. Confirm and check. Ask them to confirm the key works. My links, in the browser you created it from, shows whether the link was opened, and lets you revoke it if it wasn't.

There's a useful side effect. If someone else opens the link first, your recipient finds it already used, which tells you to revoke the key instead of leaving you with a silent leak.

If the direction is reversed and a client needs to give you their key, send them a secret request. What they paste is encrypted in their browser to a key that only your inbox link holds.

What to put in the note with the key

A bare key is hard to manage later. Add a few lines of context inside the same encrypted note, so the recipient knows what they're holding and you know what to clean up:

  • Which service and environment the key is for, and which account or project it belongs to.
  • What it can do, such as "read-only," "restricted to payments" or "sandbox only."
  • When it will be revoked, for example at the end of the contract.
  • Where it should live: "Add it to the project's secret store, not to the repository."

Keep that context inside the note rather than in the chat message that carries the link. The less the visible message says about what's behind the link, the less use it is to anyone else who sees it.

If you're the one receiving a key

  • Open the link when you're ready to store the key, because it may only open once.
  • Put the key straight into your password manager or the project's secret store, not a text file or a chat with yourself.
  • Tell the sender if the link had already been used when you opened it. Someone else got there first, and the key needs revoking.
  • If you'll need access for more than a few days, ask for a key of your own next time.

Things that look safe but aren't

HabitWhy it fails
Half the key in each of two messagesSame chat, same history: anyone with access has both halves
A password-protected zip with the password in the same emailOne compromised mailbox reveals both
A "secret" gist or an unlisted pasteAnyone with the URL can read it
A screenshot of the provider's dashboardPhotos sync to cloud backups and are hard to track down
A key in a shared doc "for now"Docs get copied, exported and forgotten

After the handoff: rotate on triggers

Rotation is what makes a leaked copy harmless. Revoke or rotate a key:

  • when someone with access leaves or changes role. Both Stripe and AWS call this out;
  • immediately after a suspected exposure. The OWASP Secrets Management Cheat Sheet says exposed keys should undergo immediate revocation, followed by a replacement and removal from code and logs;
  • when a contractor engagement or project ends;
  • if the key was ever committed to git. GitHub's guide to removing sensitive data says to revoke or rotate first, because rewriting history can't remove copies in existing clones.

Plan rotation so it doesn't break production: create the new key, deploy it, watch the old key's traffic drop to zero, then revoke it. Stripe keeps a rotated key working for up to 7 days to allow exactly this, and Google Cloud recommends rotating keys periodically and deleting keys you no longer use.

Which method fits which situation

SituationWhat to do
Teammate needs access to a providerInvite them to the account so they can create their own key
Contractor needs a key for two weeksA new restricted key, a one-read link, revocation at the end
A service or CI pipeline needs the keyYour platform's secret store, never a human handoff
Client needs to give you their keyA secret request
A key was pasted in a public channelRevoke it now, then work out how it happened
  • Machine-to-machine delivery. Servers and pipelines should read keys from a secrets manager, not from a link a person opened.
  • Ongoing shared access. If several people need the same key for months, keep it in a shared vault in your password manager, or better, give each person their own key.
  • Owner or root credentials. Don't share them. Create a scoped key instead.
  • When you need an audit trail of who read a secret. ProtectedShare can tell you that a link was opened, not who opened it.

For webhook signing secrets and other random values you generate yourself, use a secret key generator. To look inside a token you've been sent, there's a JWT decoder. Sharing a whole environment file? See how to share .env files securely.

Sources