API Keys: The Long-Lived Passwords Your Scripts Use (and Keep Losing)
TL;DR:
An API key is a password for computers. It lets one app prove to another app that it's allowed to ask questions or make changes.
Think of it like a hotel key card. No name, no photo, no signature. Just a piece of plastic with a magnetic stripe. Whoever holds the card gets into the room -- and if you drop it in the hallway, whoever picks it up walks right in.
On a good day, API keys live in secure storage like Azure Key Vault, only the right apps can read them, and they rotate on a schedule. On a bad day, somebody pastes a key into a GitHub commit, hardcodes it into an AI agent they vibe-coded last weekend, or saves it in a Notion page. Once the card's on the floor, you need to change the lock.
Beyond the Basics:
Here's what an API key actually is.
When an app needs to talk to another app's API -- say your CRM needs to pull data from your accounting system -- it has to prove it's allowed. API keys are the most common way. They're long random strings (usually 32-128 characters) passed in every request, typically in an HTTP header like Authorization: Bearer sk_live_xxxxxxxx.... The receiving app checks the key against its records and either allows or rejects.
Related credential types work the same way:
- OAuth client secrets -- paired with a client ID, used when one app authenticates to another via OAuth
- Service principal credentials (Azure / Entra ID) -- used by automated processes, not tied to a human user
- Personal access tokens (GitHub, GitLab) -- user-scoped but usable programmatically
- Bearer tokens -- the generic term for any "whoever holds this gets access" credential
API keys differ from user passwords in three important ways:
- Long-lived. User passwords rotate; API keys often live for months or years. Many live until explicitly revoked.
- No MFA. A script can't tap "Approve" on a phone. The key itself is the only barrier to access.
- Widely scoped by default. Unless the platform supports fine-grained scopes, many keys grant broad permissions.
Common ways keys leak:
- Committed to public GitHub repos. Git history is forever. Attackers run scanners that catch public keys within minutes of a push.
- Hardcoded in client-side code. Any key shipped to a browser or mobile app is public. Full stop.
- Pasted in chat or email. Slack logs, email archives, and screenshots all survive.
- Left in
.envfiles on shared drives. - Stored in Notion pages or Google Docs "just for convenience."
- Created by non-developers. AI-era twist: business users building agents in Claude Desktop, n8n, or Zapier are creating API keys for real services without understanding that a key is equivalent to a password stored in plain text.
What actually works:
- Secret managers. Azure Key Vault, AWS Secrets Manager, HashiCorp Vault, 1Password, Doppler. Keys live there, apps fetch them at runtime, humans never see them.
- Short key lifetimes with automated rotation. 30-90 days for sensitive systems.
- Least-privilege scoping. A key that can only read billing data can't also delete users.
- Secret scanning in CI/CD. GitHub's built-in scanner, or tools like Gitleaks, catch keys in commits before they hit public branches.
- Anomaly detection at the API provider. Most modern APIs flag unusual key usage patterns (new IP range, volume spike) and alert or block.
- Managed identities where possible. In Azure, managed identities let a resource authenticate to another Azure service without any key at all -- the platform handles it. No key, nothing to leak.
The best practice isn't complicated. The hard part is catching up to the sprawl that already exists -- every key in your environment that was created before you started paying attention.