# ADR-050: SHA-256 for Machine-Generated API Keys ## Status Accepted ## Context API key hashing has two common approaches: 1. **Fast hash** (SHA-256): O(1) verification at high throughput. Standard for machine-generated tokens. 2. **Slow KDF** (bcrypt, Argon2): Intentionally expensive to slow brute-force attacks. Standard for human-chosen passwords. The choice depends on the input entropy. Human passwords are low-entropy (maybe 30-40 bits of actual randomness even with complexity requirements), so brute-force is feasible unless the hash is slow. Machine-generated keys are high-entropy (128-bit+ randomness from `crypto.randomUUID()` or equivalent), making brute-force computationally infeasible even with a fast hash. ## Decision Use SHA-256 for API key hashing. Do not use bcrypt or Argon2. The API keys in `@alkdev/storage` are machine-generated secrets with 128-bit+ entropy. An attacker attempting to brute-force a SHA-256 hash of such a key faces 2^128 possible inputs — infeasible regardless of hash speed. Slow KDFs add latency (50-200ms per verification) without meaningful security improvement for high-entropy inputs. ## Consequences **Positive:** - Fast O(1) verification — critical for high-throughput API authentication - Widely supported — every language/runtime has SHA-256 built in - Simple implementation — no salt generation, no cost parameter tuning **Negative:** - If a consumer generates low-entropy keys (short, predictable patterns), SHA-256 provides less protection against brute-force than a slow KDF. This is a consumer responsibility — the storage table schema cannot enforce key generation quality. - SHA-256 is not post-quantum resistant. This is acceptable for API keys, which can be rotated, unlike passwords which are often long-lived. ## References - `api_keys.keyHash` in [sqlite-host.md](../sqlite-host.md) - Hub ADR-010: SHA-256 for API key hashing (same decision, provenance)