Identity tables were derived from hub's PostgreSQL schema but simplified without documenting what was removed or why. This restructures them for the current auth landscape (API key + wraith SSH/cert-authority): - ADR-049: Separate api_keys and peer_credentials tables (different lookup patterns, columns, lifecycles), remove Gitea columns, map hub data→metadata - ADR-050: Extract SHA-256 vs KDF decision from inline spec text - Add peer_credentials table for SSH key and cert-authority auth - Specify all FK cascade behaviors within system DB (RESTRICT, CASCADE, SET NULL) - Complete index specifications for all identity tables - Add scope boundary section (storage owns schemas, not auth/authorization) - Update audit_logs with credentialId+credentialType polymorphic reference - Add 3 new open questions (OQ-33/34/35) for credential type expansion
52 lines
1.9 KiB
Markdown
52 lines
1.9 KiB
Markdown
# 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) |