Hash client auth tokens with SHA-256 before storing in the database. When validating tokens, hash the incoming token and compare against the stored hash. This prevents token exposure if the database is compromised.
Existing plaintext tokens are implicitly invalidated since they will not match the new hashed lookups — users will need to create new sessions.
Changes
internal/db/queries.go: Added hashToken() helper using crypto/sha256. Updated CreateSession to store hashed token. Updated GetSessionByToken to hash the incoming token before querying.
internal/db/auth.go: Updated RegisterUser and LoginUser to store hashed tokens.
Migration
No schema changes needed. The token column remains TEXT but now stores 64-char hex SHA-256 digests instead of 64-char hex random tokens. Existing plaintext tokens are effectively invalidated.
## Summary
Hash client auth tokens with SHA-256 before storing in the database. When validating tokens, hash the incoming token and compare against the stored hash. This prevents token exposure if the database is compromised.
Existing plaintext tokens are implicitly invalidated since they will not match the new hashed lookups — users will need to create new sessions.
## Changes
- **`internal/db/queries.go`**: Added `hashToken()` helper using `crypto/sha256`. Updated `CreateSession` to store hashed token. Updated `GetSessionByToken` to hash the incoming token before querying.
- **`internal/db/auth.go`**: Updated `RegisterUser` and `LoginUser` to store hashed tokens.
## Migration
No schema changes needed. The `token` column remains `TEXT` but now stores 64-char hex SHA-256 digests instead of 64-char hex random tokens. Existing plaintext tokens are effectively invalidated.
closes https://git.eeqj.de/sneak/chat/issues/34
Hash client tokens with SHA-256 before storing in the database.
When validating tokens, hash the incoming token and compare against
the stored hash. This prevents token exposure if the database is
compromised.
Existing plaintext tokens are implicitly invalidated since they
will not match the new hashed lookups.
Changes:
- Add hashToken() helper using crypto/sha256
- Hash tokens in CreateSession, RegisterUser, LoginUser before INSERT
- Hash incoming token in GetSessionByToken before SELECT
PR:#69 — feat: store auth tokens as SHA-256 hashes instead of plaintext Issue:#34 — [security] Store auth tokens as SHA-256 hashes instead of plaintext
Summary
Clean, minimal, correct implementation. All token storage and lookup paths are covered.
✅RegisterUser (auth.go) — Hashes token before INSERT into clients. Plaintext token returned to caller.
✅LoginUser (auth.go) — Hashes token before INSERT into clients. Plaintext token returned to caller.
✅No plaintext leaks — All 3 INSERT paths and the 1 SELECT path use tokenHash. No other token storage/query paths exist in the codebase.
✅No modifications to Makefile, .golangci.yml, CI config, or test assertions.
✅Only 2 files changed — internal/db/queries.go and internal/db/auth.go. No scope creep.
✅Migration note — PR body correctly documents that existing plaintext tokens are implicitly invalidated. No schema change needed since the column type remains TEXT.
✅docker build . passes (lint, fmt-check, tests all green).
Notes
The token column stores 64-char hex SHA-256 digests (same length as the previous 64-char hex random tokens), so no schema change is needed.
Existing sessions will be invalidated, which is acceptable for a pre-1.0 project and is documented in the PR description.
No issues found. Ready to merge.
## Code Review — PASS ✅
**PR:** [#69](https://git.eeqj.de/sneak/chat/pulls/69) — feat: store auth tokens as SHA-256 hashes instead of plaintext
**Issue:** [#34](https://git.eeqj.de/sneak/chat/issues/34) — [security] Store auth tokens as SHA-256 hashes instead of plaintext
### Summary
Clean, minimal, correct implementation. All token storage and lookup paths are covered.
### Checklist
- ✅ **`hashToken()` helper** — Correctly uses `crypto/sha256` + `hex.EncodeToString`, returns lowercase hex digest. Simple and correct.
- ✅ **`CreateSession`** (`queries.go`) — Hashes token before INSERT into `clients`. Plaintext token returned to caller.
- ✅ **`GetSessionByToken`** (`queries.go`) — Hashes incoming token before SELECT query. Lookup matches stored hash.
- ✅ **`RegisterUser`** (`auth.go`) — Hashes token before INSERT into `clients`. Plaintext token returned to caller.
- ✅ **`LoginUser`** (`auth.go`) — Hashes token before INSERT into `clients`. Plaintext token returned to caller.
- ✅ **No plaintext leaks** — All 3 INSERT paths and the 1 SELECT path use `tokenHash`. No other token storage/query paths exist in the codebase.
- ✅ **No modifications** to Makefile, `.golangci.yml`, CI config, or test assertions.
- ✅ **Only 2 files changed** — `internal/db/queries.go` and `internal/db/auth.go`. No scope creep.
- ✅ **Migration note** — PR body correctly documents that existing plaintext tokens are implicitly invalidated. No schema change needed since the column type remains `TEXT`.
- ✅ **`docker build .`** passes (lint, fmt-check, tests all green).
### Notes
- The token column stores 64-char hex SHA-256 digests (same length as the previous 64-char hex random tokens), so no schema change is needed.
- Existing sessions will be invalidated, which is acceptable for a pre-1.0 project and is documented in the PR description.
No issues found. Ready to merge.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
Hash client auth tokens with SHA-256 before storing in the database. When validating tokens, hash the incoming token and compare against the stored hash. This prevents token exposure if the database is compromised.
Existing plaintext tokens are implicitly invalidated since they will not match the new hashed lookups — users will need to create new sessions.
Changes
internal/db/queries.go: AddedhashToken()helper usingcrypto/sha256. UpdatedCreateSessionto store hashed token. UpdatedGetSessionByTokento hash the incoming token before querying.internal/db/auth.go: UpdatedRegisterUserandLoginUserto store hashed tokens.Migration
No schema changes needed. The
tokencolumn remainsTEXTbut now stores 64-char hex SHA-256 digests instead of 64-char hex random tokens. Existing plaintext tokens are effectively invalidated.closes sneak/chat#34
Code Review — PASS ✅
PR: #69 — feat: store auth tokens as SHA-256 hashes instead of plaintext
Issue: #34 — [security] Store auth tokens as SHA-256 hashes instead of plaintext
Summary
Clean, minimal, correct implementation. All token storage and lookup paths are covered.
Checklist
hashToken()helper — Correctly usescrypto/sha256+hex.EncodeToString, returns lowercase hex digest. Simple and correct.CreateSession(queries.go) — Hashes token before INSERT intoclients. Plaintext token returned to caller.GetSessionByToken(queries.go) — Hashes incoming token before SELECT query. Lookup matches stored hash.RegisterUser(auth.go) — Hashes token before INSERT intoclients. Plaintext token returned to caller.LoginUser(auth.go) — Hashes token before INSERT intoclients. Plaintext token returned to caller.tokenHash. No other token storage/query paths exist in the codebase..golangci.yml, CI config, or test assertions.internal/db/queries.goandinternal/db/auth.go. No scope creep.TEXT.docker build .passes (lint, fmt-check, tests all green).Notes
No issues found. Ready to merge.