patterntypescriptCritical
API Key Management: Hashed storage, scopes, and rotation workflows
Viewed 0 times
api-keyshashingscopesrotationsecurityleast-privilegesha256
Error Messages
Problem
Storing API keys in plaintext means a database breach exposes all consumer credentials. APIs without key scopes give every integration full access. Missing rotation workflows leave revoked keys as security liabilities.
Solution
Store only the SHA-256 hash of API keys — show the full key only once at creation. Associate keys with scopes (read, write, admin) and expiry. Implement a rotation endpoint that creates a new key and gives a grace period before invalidating the old one.
Why
Hashed storage follows the same principle as password hashing — the server should not be able to reconstruct the secret. Scopes implement least-privilege. Rotation workflows remove friction from security hygiene.
Gotchas
- Use a prefix on API keys (sk_live_, pk_test_) to make them machine-identifiable in logs and prevent accidental commit.
- Include a hint (last 4 chars) in the stored record so users can identify which key is which without exposing the full key.
- Never log full API keys — scrub them from request logs at the middleware level.
Code Snippets
API key creation with hashing and prefix
import { randomBytes, createHash } from 'crypto'
function generateApiKey(prefix = 'sk_live') {
const raw = `${prefix}_${randomBytes(32).toString('hex')}`
const hash = createHash('sha256').update(raw).digest('hex')
const hint = raw.slice(-4)
return { raw, hash, hint } // store hash+hint, return raw once
}
async function verifyApiKey(raw: string): Promise<ApiKey | null> {
const hash = createHash('sha256').update(raw).digest('hex')
return db.apiKeys.findOne({ hash, revokedAt: null })
}Revisions (0)
No revisions yet.