Skip to content

feat(totp): move TOTP management to the /mfa/totp/* routes - #126

Open
clouserw wants to merge 1 commit into
mainfrom
mfa-totp-routes
Open

clouserw wants to merge 1 commit into
mainfrom
mfa-totp-routes

Conversation

@clouserw

@clouserw clouserw commented Sep 25, 2026 •

Copy link
Copy Markdown
Member

Summary

The auth-server's pre-MFA TOTP routes are going away. POST /totp/destroy was removed in January 2026 (mozilla/fxa 985f565dc9), so Session.totp_delete has been returning 404 since then, and POST /totp/create is being retired under FXA-14626. PyFxA was the last first-party caller of /totp/create.

This moves TOTP management onto the /mfa/totp/* routes, which are guarded by a short-lived MFA JWT instead of the session token.

Changes

  • Session.mfa_request_otp(action) and Session.mfa_verify_otp(code, action): request the emailed one-time code and exchange it for the MFA token.
  • Session.totp_create(mfa_token) and Session.totp_delete(mfa_token) now call /mfa/totp/create and /mfa/totp/destroy. Breaking: both take the MFA token.
  • Session.totp_setup_verify(mfa_token, code) and Session.totp_setup_complete(mfa_token) cover the setup flow; nothing is stored on the account until complete succeeds.
  • Live test_totp rewritten around the MFA flow. The code arrives in the X-Account-Change-Verify-Code email header.
  • Mocked test pins that the MFA call site sends the raw JWT as a plain Bearer token, not the prefixed session token.
  • CHANGES.txt entry under 0.9.0 (unreleased); no version bump here.

Notes

  • The old live test asserted TOTP exists right after create. That has been false since the server moved pending secrets into Redis, so it was already failing against stage. The new test asserts current behaviour.
  • totp_exists and totp_verify are unchanged; /totp/exists and /session/verify/totp are not being retired.
  • Live test not run here (needs FXA_RUN_LIVE_TESTS=1, stage, and restmail). Mocked suite: 6 passed, 30 skipped.

Related: FXA-14626, FXA-12699.

Because:

* The auth-server removed POST /totp/destroy in January 2026, so
  Session.totp_delete has returned 404 since then.
* POST /totp/create is being retired now that traffic has moved to
  /mfa/totp/create (FXA-14626); PyFxA was its last first-party caller.

This commit:

* Adds Session.mfa_request_otp and mfa_verify_otp to obtain the MFA JWT
  that guards the /mfa/* routes.
* Points totp_create and totp_delete at /mfa/totp/create and
  /mfa/totp/destroy; both now take the MFA token.
* Adds totp_setup_verify and totp_setup_complete for the setup flow.
* Rewrites the live TOTP test around the MFA flow and adds a mocked test
  pinning the plain Bearer header on the MFA call site.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

MFA JWTs can be transmitted over plaintext HTTP, and most new call paths lack default-CI coverage.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 1 High severity · 1 Low severity

Open (2)
What changed in this PR

Moves TOTP lifecycle management to MFA JWT-protected routes.

Changes:

  • Adds MFA OTP request and verification helpers.
  • Migrates TOTP creation, setup, and deletion to /mfa/totp/*.
  • Updates live and mocked tests plus release notes.
File Description
fxa/​core.py Implements MFA-token TOTP APIs.
fxa/​tests/​test_core.py Updates live flow and adds bearer-header coverage.
CHANGES.txt Documents the breaking API migration.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread fxa/core.py
from fxa.errors import ClientError
from fxa._utils import (
APIClient,
BearerTokenAuth,
Comment thread fxa/tests/test_core.py
Comment on lines +465 to +466
@responses.activate
def test_totp_setup_sends_plain_bearer_mfa_token(self):
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants