Repository navigation
Description
What
ChangePassword, ConfirmPasswordReset and UpdateUserProfile (internal/auth/service_password.go, service_user.go) persist the new password hash, then invalidate sessions and API keys (invalidateUserCredentialsBestEffort) as a separate, best-effort step: failures are logged, not returned, and never roll back the password change. This has been the behavior for session invalidation since before #102/#392 and now also applies to the API-key revocation added there.
Why this matters
If DeleteUserSessions or RevokeAllUserAPIKeys fails (partially or entirely) after a successful UpdateUser, the new password takes effect but old sessions and/or API keys can remain valid until they naturally expire. For the threat model in #102 (an attacker who briefly held a victim's session and minted an API key), this narrows but does not fully close the window: a transient store failure at exactly the wrong moment leaves the attacker's key alive even though the victim successfully changed their password.
Why it wasn't fixed as part of #392
- No transaction-capable store interface exists (
internal/auth/interfaces.go,store_postgres.go) to atomically commit the password update and the credential-invalidation writes together; adding one is a genuine store-layer change, not a scoped fix. - Making invalidation fail-closed (block/rollback the password change on invalidation failure) without fixing session invalidation the same way would be an inconsistent half-measure, and blocking a victim's urgent password rotation on a transient API-key-store failure is arguably worse for this exact attack scenario than the current narrow residual window.
Suggested direction
- Add a
WithTx-style capability toStoreInterface(or an equivalent single write that updates the user row and marks sessions/keys revoked together), OR - Introduce a persisted "credential version" / "password generation" counter on
UserthatValidateSessionandValidateUserAPIKeycheck against, so revocation becomes implicit in the password-hash write itself rather than a separate best-effort pass over sessions/keys.
Raised by CodeRabbit on #392 (#392 (comment), #discussion_r4119975933); the reordering fix in that PR ensures a failed password persist no longer revokes valid credentials, but does not address invalidation itself failing after persistence succeeds.
Activity
IAmJSD commentedon Oct 20, 2026
Claiming: working on this
fix(auth): reject sessions issued before the user's last password cha…