Legacy GitHub bindings stored the login name, while current bindings store
the numeric account ID. A legacy match no longer signs the user in on its
own. When the account has two-factor or a passkey, the binding is rewritten
only after that verification completes, inside the transaction that issues
the session. Otherwise it is rewritten when one of the GitHub account's
verified emails matches the account email. Without either, the login is
declined with guidance to sign in another way and relink GitHub in account
settings. All-digit login names never take part in the comparison, the bind
flow no longer compares login names, and every migration or declined
attempt is recorded as an account binding audit event.
Treat TOTP and Passkey as alternative enrolled factors across login and
sensitive account operations. Gate every primary login transport before
issuing a session, require WebAuthn user verification, and consume login
challenges atomically with session creation.
Reuse the shared verification UI for login, 2FA management, and account
deletion. Require scoped, single-use deletion proof; recheck the session
inside the deletion transaction and revoke all sessions afterward.
Validation: controller/service/model/middleware tests; real SQLite 3.50.4,
MySQL 8.4.11, and PostgreSQL 16.15 security regressions; frontend tests,
TypeScript, targeted lint, formatting, and production build.
Deploy the frontend and all backend nodes together. No schema changes.