Sangeetha-Grantha

Metadata Value
Status Completed
Version 2.0.0
Last Updated 2026-06-13
Author Sangeetha Grantha Team
Priority P0 — Blocker (north-star N1)
Epic TRACK-109 (W6 Security)
Decisions D3 (decision log)
Depends on none
Blocks TRACK-110 (admin-user bootstrap hash)
Split out to TRACK-119 (interactive login, rehash-on-login wiring, throttling, shared-token/roles fix)

TRACK-114: Authentication Hardening — Password Hashing (N1)

Goal

Replace the plaintext hashPassword() (UserManagementService.kt:143, returned its input verbatim with a // NOT SECURE TODO) with argon2id, so no password is stored in plaintext at rest, and expose a shared PasswordHasher helper that TRACK-110’s admin bootstrap reuses. Estimated ~0.5 day; execute first.

Re-scoped 2026-06-13. Investigation found that login does not verify a password — POST /v1/auth/token (AuthRoutes.kt) is gated by a shared ADMIN_TOKEN and issues a JWT with caller-supplied roles, checking no credential. The N1 framing (“JWT issuance sits on top of plaintext credentials”) therefore does not match the code, and the real escalation risk is the shared-token + self-assigned-roles path. Given the chosen future direction is passwordless (OAuth/OTP), a full password-login flow would be throwaway work. This track is scoped to securing the hash at rest only; interactive login, rehash-on-login wiring, login throttling, and the shared-token / caller-roles fix are split out to TRACK-119. See [[auth-future-direction]].

Context

North-star finding N1 (Blocker): credentials stored in plaintext at rest. Decision D3 selected argon2id. The shared PasswordHasher also ships verifyAllowingLegacy (returns a needsRehash flag) so the future interactive login (TRACK-119) can do rehash-on-login without redesign — but nothing verifies passwords today, so that path is intentionally dormant.

Implementation Plan

Phase 1 — Hashing (done)

Phase 2 — Tests (done)

Deferred to TRACK-119 (interactive auth)

Acceptance Criteria

Docs to Update

References