API Authentication with API Keys

intermediate
11 min

API Authentication with API Keys

An open API is an invitation to abuse: scraped data, drained quotas, surprise bills. The simplest widely used defense is the API key, a long random secret issued to each client. Weather services, map providers, and payment processors all start here. In this lesson we cover how API keys work, how to implement them properly, and where their limits lie.

What an API Key Is

An API key is an opaque random string, such as cyc_live_4f8a2b91c6d3..., that identifies and authenticates a calling application. The client includes it on every request; the server looks it up, confirms it is active, and attaches the owning account to the request. Prefixes like live and test, popularized by Stripe, let both humans and log scanners recognize a key's environment at a glance.

Note the emphasis on application: a key identifies a program or a customer account, not an individual human user. That distinction drives most of the trade-offs below.

Where to Send the Key

Three transport options exist, in descending order of preference:

  • Custom header (best): X-API-Key: cyc_live_... keeps the secret out of URLs and separates it from other auth schemes.
  • Authorization header: Authorization: Bearer cyc_live_... works and reuses standard tooling.
  • Query string (avoid): ?api_key=... leaks the secret into server logs, browser history, proxies, and Referer headers.

Always require HTTPS; over plain HTTP any header is readable by everyone on the network path.

Server-Side Implementation Done Right

The naive approach stores keys in a database column and compares strings. Production systems do three things differently.

Hash stored keys. Treat keys like passwords: store only a hash, so a leaked database does not leak usable credentials. Keep the first few characters in plaintext as a displayable hint (cyc_live_4f8a...).

Compare in constant time. Ordinary string comparison exits at the first mismatched character, letting attackers measure timing to guess keys byte by byte. Use your language's constant-time comparison, like crypto.timingSafeEqual in Node.

Attach metadata. A key row should carry its owner, creation date, optional expiry, per-key rate limits, and scopes (read-only versus read-write), so you can reason about and restrict each credential independently.

javascript
// Express middleware sketch async function requireApiKey(req, res, next) { const key = req.get('X-API-Key'); if (!key) return res.status(401).json({ error: { code: 'missing_api_key', message: 'X-API-Key header required' } }); const record = await keys.findActiveByHash(sha256(key)); if (!record) return res.status(401).json({ error: { code: 'invalid_api_key', message: 'Unknown or revoked key' } }); req.account = record.account; next(); }

Lifecycle: Issue, Rotate, Revoke

Generate keys with a cryptographically secure random source (at least 32 bytes), show the full value exactly once at creation, and never email it. Support rotation by allowing two active keys per account, so customers can deploy the new key before revoking the old one with zero downtime. Revocation must take effect immediately, which is a genuine advantage keys hold over stateless tokens.

On the client side, keys live in environment variables or secret managers, never in source code. A hardcoded key in a public GitHub repo is typically discovered by scanners within minutes.

What API Keys Cannot Do

Keys authenticate applications, not users, so they cannot express "Alice can edit only her own documents." They carry no expiry or claims by themselves, and every request costs a database lookup. When you need per-user identity, sessions that expire, and claims the server can verify without storage, you need tokens, which is exactly where the next lesson picks up.

Key Takeaways

  • API keys identify applications; send them in headers over HTTPS, never in query strings.
  • Store hashes, compare in constant time, and attach owner, scopes, and limits to each key.
  • Design for rotation with overlapping keys and instant revocation.
  • For per-user identity and expiring sessions, step up to JWT authentication.

Next up: JWT Authentication, token-based auth for real user sessions.

API Authentication with API Keys - REST APIs | CodeYourCraft | CodeYourCraft