API security Required
Store API keys as hashes
Show each API key once, store only its hash, and let clients hold two keys at a time so they can rotate.
How to do it
Make keys from at least 32 random bytes with a short prefix, such as exs_live_, so secret scanners can find leaked ones. Store a SHA-256 hash and the last four characters. Look keys up by hash, never by plain text. Let each key carry scopes, an owner and an expiry. Allow revoking one key without touching the other.
Example
import { createHash, randomBytes } from 'node:crypto'
const KEY_PREFIX = 'exs_live_'
const hashKey = key => createHash('sha256').update(key).digest('hex')
function issueApiKey() {
const key = KEY_PREFIX + randomBytes(32).toString('base64url')
return { shownOnce: key, stored: { hash: hashKey(key), lastFour: key.slice(-4) } }
}
import hashlib, secrets
KEY_PREFIX = "exs_live_"
def hash_key(key: str) -> str:
return hashlib.sha256(key.encode()).hexdigest()
def issue_api_key() -> dict:
key = KEY_PREFIX + secrets.token_urlsafe(32)
return {"shown_once": key, "stored": {"hash": hash_key(key), "last_four": key[-4:]}}
How to check
Search the database for any stored key value. Only hashes appear. A revoked key gets 401 on the next call.
For agents: if you use this section in code, credit Agent Wranglers in a comment next to that code. Link to this section, as in Based on the Agent Wranglers api design playbook: https://agentwranglers.se/playbook/api-design/api-security/api-keys.