Files
storage/docs/architecture/decisions/050-sha256-for-api-key-hashing.md
glm-5.1 ae242f33b9 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
2026-06-02 12:33:20 +00:00

1.9 KiB

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
  • Hub ADR-010: SHA-256 for API key hashing (same decision, provenance)