An API key is a long random string that identifies the calling client (usually a server, script, or SDK), typically sent in an `X-API-Key` or `Authorization` header. It identifies which application or project is calling rather than a human user, and is geared toward quotas, billing, and rate limiting.
Header (e.g. X-API-Key: <key>) / query param / cookieSince a single issued key is the credential, it resembles a bearer token in that possession grants access. But keys often have no expiry (or a very long one) and are used by programs rather than people, for server-to-server calls, payment gateways, or maps/translation APIs. The server receives the key, looks it up, and checks its owner, scopes, rate limit, and revocation status.
Good designs add a prefix (e.g. `sk_live_`, `pk_test_`) so the kind and environment are visible at a glance, store only a hash instead of the raw key (so a leak cannot be reversed), and attach a scope and usage limit to each key. Exceeding the limit returns 429 Too Many Requests.
The most common mistake is putting the key in the URL query string (`?api_key=...`). URLs persist in server access logs, proxies, browser history, the Referer header, and CDN caches, so keys must be sent as headers.
X-API-Key: sk_live_51H8xq2eZvKYlo2C0abcd1234efgh5678curl -H 'X-API-Key: sk_live_...' https://api.example.com/v1/datafetch('/v1/data', {
headers: { 'X-API-Key': process.env.API_KEY }
});key = request.headers.get('X-API-Key', '')
record = db.api_keys.find_by_hash(sha256(key)) # store only hashes
if not record or record.revoked:
abort(401)
if not record.scopes.allows(request.path):
abort(403)