Restructure identity tables: separate credential types, add peer_credentials, specify FK cascades and indexes
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
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
# 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)
|
||||
Reference in New Issue
Block a user