API key
A long random string that lets one program call another as your account. No login screen, no user, just the secret.
See it
What it is
An API key is a long random string that identifies a machine caller. No login screen, no expiry by default, no user sitting there: a script sends the key on every request and your server looks up which account it belongs to. Stripe's sk_live and OpenAI's sk- keys are the canonical shape, and the prefix matters, because it lets people (and GitHub's secret scanner) recognize a leaked key on sight.
Reach for keys when the caller is a server, a CLI, or a cron job that no human will babysit. When there is a user sitting there to ask, use OAuth instead: what a static key cannot express is the interactive delegated consent OAuth is built around, the 'this specific human said yes to that specific thing, and can take it back' part. A key is not automatically account-wide, though. A well-built one carries its own permissions, resource and environment restrictions, and an expiry date, and it is a design failure rather than a law of nature when it does not. Generate them per integration with the least privilege that integration needs, show the full value exactly once, store only a hash plus a short display prefix, and support rotation with an overlap window so nothing breaks mid-swap.
The classic mistake is shipping one in frontend code or a mobile app. Anything the browser can send, a user can read in devtools, so a 'secret' key in client JavaScript is a public key with extra steps. If the browser needs it, proxy the call through your own server or use a separate publishable key that can only do harmless things.
Ask AI for it
Add API key auth for machine callers. Issue keys in the shape sk_live_<random-key-id>.<32-byte-secret>, where the key ID is a public lookup handle and the part after the dot is the actual secret, both from a CSPRNG. Store the key ID in the clear alongside a SHA-256 hash of the secret, a name, the owning account, a scope list, an optional expires_at, and created_at plus last_used_at audit timestamps. Never store the secret itself. Display keys as sk_live_<key-id> so every key is distinguishable in the dashboard, since a fixed prefix like 'sk_live_' is identical across all of them and useless for telling two keys apart, and show the full secret exactly once at creation. Authenticate an 'Authorization: Bearer <key>' header by splitting on the dot, looking the record up by key ID, then comparing the secret hash in constant time. Enforce the key's scopes on every route, rate limit per key, and support revoke plus rotate-with-overlap in the dashboard. Never expose a key to client-side code.