-
Notifications
You must be signed in to change notification settings - Fork 0
Tech Story: Hash refresh tokens at rest in the database #96
Copy link
Copy link
Open
Labels
backendBackend services and logicBackend services and logicdatabaseSchema, migrations, indexingSchema, migrations, indexingsecuritySecurity, auth, and permissionsSecurity, auth, and permissionstech-storyTechnical implementation storyTechnical implementation story
Milestone
Description
Tech Story
As a platform engineer, I want refresh tokens stored as hashes in the database so that a database breach does not yield usable tokens that could be used to impersonate users.
Context
Refresh tokens are currently stored as plaintext crypto.randomBytes(32) hex strings. If the refresh_tokens table is compromised (SQL injection, backup leak, rogue DB access), every active user session can be hijacked. Storing the SHA-256 hash of the token instead means the raw token is never persisted — only the bearer of the original token can produce the correct hash.
Acceptance Criteria
-
generateRefreshToken()storessha256(token)in the DB, returns the raw token to the caller -
refreshAccessToken()hashes the incoming token before looking it up in the DB -
revokeRefreshToken()hashes the incoming token before the update query - No raw token value ever written to the database or application logs
- Existing plaintext tokens in DB become invalid after deploy (users must re-login — acceptable)
- No migration required — column type unchanged (
text), only stored value changes
Technical Elaboration
function hashToken(raw: string): string {
return crypto.createHash('sha256').update(raw).digest('hex');
}- Call
hashToken(token)before everysaveandfindOne/updateinvolving the token column - The entity column name stays
token; no schema migration needed - Add a unique index on
refresh_tokens.tokenif one does not already exist (the hash is effectively a unique identifier)
Notes
- SHA-256 is appropriate here (not bcrypt) because: the input has high entropy (32 random bytes) so rainbow tables are infeasible, and lookup performance matters (bcrypt is intentionally slow)
- Do not log the raw token at any point in the token lifecycle
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
backendBackend services and logicBackend services and logicdatabaseSchema, migrations, indexingSchema, migrations, indexingsecuritySecurity, auth, and permissionsSecurity, auth, and permissionstech-storyTechnical implementation storyTechnical implementation story