Resolves#16770
The MFA login token redemption path (`POST /api/latest/fleet/sessions`)
read the one-time verification token with a non-locking `SELECT` on the
read replica, then created a session and deleted the token in a
*separate* transaction without verifying the token was still present.
Concurrent requests carrying the same token each passed the `SELECT` and
each minted a distinct session, breaking the single-use guarantee.
`SessionByMFAToken` now consumes the token and creates the session
inside a single transaction:
- The token row is locked with `SELECT ... FOR UPDATE`, then deleted,
and the delete's rows-affected count is confirmed non-zero before the
session is created.
- Concurrent redemptions serialize on the row lock; the loser re-reads
after the winner commits the delete, finds no row, and aborts before
creating a session.
- The user is still loaded *before* the transaction, so a
concurrently-deleted user or a transient read error leaves the token
intact for retry (preserving the pre-fix atomicity behavior).
---------
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Juan Fernandez <juan@fleetdm.com>