fix(settings): add a real, reachable entry point to 2FA setup - #335
Merged
Conversation
Reported directly by the user: "There is not place to configure OAuth
or 2FA."
The 2FA setup flow (/2fa/setup) itself fully works. The only place in
the entire frontend that ever linked to it was
frontend/templates/dashboard.html's "Security Settings" section — and
that template is unreachable: /dashboard just redirects to / (302),
and / renders index.html, a completely different template with no
equivalent section. dashboard.html has been dead weight with no route
serving it.
Also found and worked around while investigating: settings.html
already has an entire second, separate "Enable 2FA" flow — a
JS-generated modal (#twoFactorModal, built via insertAdjacentHTML) and
a stale target element (id="twoFactorStatus") inside an already-known-
dead adminUserManagement-adjacent code block (missing DOM elements,
confirmed unreachable during an earlier v1.0.0 task). Nothing calls
openModal('twoFactorModal') anywhere, so that flow is equally
unreachable and unverified — left untouched rather than trying to
resurrect a second, potentially-stale implementation; used a distinct
element ID (securityTwoFactorStatus) to guarantee no collision with it.
Adds a real "Two-Factor Authentication" section to the Settings page:
status (enabled/disabled, backup codes remaining) loaded from the
existing, correctly-authenticated GET /2fa/api/status endpoint, and a
working link to /2fa/setup when not yet enabled. Deliberately does NOT
add an inline disable button — POST /2fa/api/disable verifies the
caller's password against a different, potentially-stale credential
store than the one they actually log in with (filed separately as
#334), so building UI on top of it now would just surface that bug to
more users.
OAuth's equivalent gap (there's no UI to configure provider client_id/
secret/redirect_uri at all — 100% settings-table-driven with no admin
form anywhere) is real but larger in scope and tracked separately, not
addressed in this commit.
No backend changes. Full suite: 123 passed, 1 skipped, unchanged.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This was referenced Aug 11, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Reported directly by the user: "There is not place to configure OAuth or 2FA."
The
/2fa/setupflow itself fully works — the only place that ever linked to it,dashboard.html's "Security Settings" section, is unreachable (/dashboardredirects to/, which renders a completely different template). Adds a real "Two-Factor Authentication" section to Settings: live status fromGET /2fa/api/status, and a working link to/2fa/setupwhen not enabled.Also found while investigating:
settings.htmlalready has a second, separate 2FA-enable flow (a JS-generated modal,insertAdjacentHTML) inside an already-known-dead code block from an earlier task — nothing callsopenModal('twoFactorModal')anywhere. Left untouched rather than resurrecting a second, unverified implementation; used a distinct element ID to guarantee no collision.Deliberately not included: an inline "disable 2FA" button —
POST /2fa/api/disableverifies the password against a different, potentially-stale credential store than the one you actually log in with (filed as #334). Building UI on that now would just expose more people to it.OAuth's equivalent gap (no UI to configure provider credentials at all) is real but bigger in scope — tracked separately, not in this PR.
Test plan
Co-Authored-By: Claude Sonnet 5 noreply@anthropic.com