Skip to content

chore: migrate 2FA TOTP DDP methods to /v1/users.totp.* REST endpoints - #40734

Merged
ggazzo merged 10 commits into
developfrom
chore/ddp-migrate-batch5-2fa
Jul 24, 2026
Merged

chore: migrate 2FA TOTP DDP methods to /v1/users.totp.* REST endpoints#40734
ggazzo merged 10 commits into
developfrom
chore/ddp-migrate-batch5-2fa

Conversation

@ggazzo

@ggazzo ggazzo commented May 29, 2026

Copy link
Copy Markdown
Member

Summary

Continues the DDP→REST sweep (#40659, #40711, #40675, #40724, #40728). This batch migrates the five 2fa:* TOTP DDP methods that backed account/security/TwoFactorTOTP. DDP methods stay registered for external SDK/mobile clients with deprecation logs pointing at the new routes.

New endpoints

DDP method REST endpoint Body Response
2fa:enable POST /v1/users.totp.enable { secret, url }
2fa:disable POST /v1/users.totp.disable { code } { disabled }
2fa:validateTempToken POST /v1/users.totp.validate { code } { codes }
2fa:regenerateCodes POST /v1/users.totp.regenerateCodes { code } { codes }
2fa:checkCodesRemaining GET /v1/users.totp.codesRemaining { remaining }

All five extract the original method body into a shared function (apps/meteor/app/2fa/server/functions/totp.ts) reused by both DDP + REST entrypoints.

Validate flow note

validate keeps the DDP-era post-enable login-token rotation: REST forwards the caller's X-Auth-Token (this.token) so non-PAT tokens get revoked just like the DDP path did via this.connection.httpHeaders['x-auth-token'].

Client changes

TwoFactorTOTP.tsx swapped five useMethod hooks for five useEndpoint hooks. Disable response shape changed from bare boolean to { disabled: boolean }; verify/regenerate continue to return { codes }.

Test plan

  • CI green (lint + typecheck pass)
  • Account → Security → Two-factor authentication → toggle on → QR appears, scan, verify code → backup codes modal renders
  • Re-load page → "You have N codes remaining" reads right
  • Regenerate backup codes → modal with new codes
  • Toggle 2FA off → enter current code → success toast; reload to confirm disabled state
  • Validate path revokes other login tokens (open second tab, validate, second tab gets kicked)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added new REST API endpoints for TOTP two-factor management (enable/disable, validate setup codes, regenerate backup codes, and check remaining backup codes).
    • Updated the account security TOTP UI to use the new REST endpoints with improved invalid-code handling and rate limiting.
  • Documentation
    • Documented the new TOTP REST endpoints and that legacy DDP TOTP methods remain available until version 9.0.0 (with deprecation logging).

Task: ARCH-2268

@dionisio-bot

dionisio-bot Bot commented May 29, 2026

Copy link
Copy Markdown
Contributor

Looks like this PR is not ready to merge, because of the following issues:

  • This PR is targeting the wrong base branch. It should target 8.8.0, but it targets 8.7.0

Please fix the issues and try again

If you have any trouble, please check the PR guidelines

@changeset-bot

changeset-bot Bot commented May 29, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 6cf199e

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
@rocket.chat/meteor Minor
@rocket.chat/rest-typings Minor
@rocket.chat/core-typings Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai

coderabbitai Bot commented May 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

TOTP account management now uses authenticated REST endpoints backed by shared server functions. REST typings, request validation, rate limiting, client response handling, DDP delegation with deprecation logging, and migration release notes are added.

Changes

TOTP DDP to REST Migration

Layer / File(s) Summary
REST type contracts for TOTP endpoints
packages/rest-typings/src/v1/users.ts
Adds typed enable, disable, validate, regenerate-codes, and remaining-codes routes with request and response payloads.
Shared TOTP server functions
apps/meteor/app/2fa/server/functions/totp.ts
Adds user validation and server operations for enabling, disabling, validating setup tokens, regenerating backup codes, and counting remaining codes.
REST TOTP routes
apps/meteor/server/api/v1/users.ts
Adds authenticated TOTP routes with AJV schemas, rate limiting for code operations, and standardized responses.
Client migration to REST endpoints
apps/meteor/client/views/account/security/TwoFactorTOTP.tsx
Replaces DDP method calls with REST endpoint hooks and adapts payloads, responses, backup-code modals, and invalid-code handling.
Deprecated DDP delegation
apps/meteor/server/meteor-methods/auth/*.ts
Routes legacy TOTP methods through shared functions and records deprecation metadata.
Changeset entries
.changeset/*.md
Documents package version bumps, REST routes, and the deprecation timeline for legacy DDP methods.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant TwoFactorTOTP
  participant APIv1Users
  participant TOTPFunctions
  participant UsersModel
  TwoFactorTOTP->>APIv1Users: submit TOTP operation
  APIv1Users->>TOTPFunctions: pass authenticated user and code
  TOTPFunctions->>UsersModel: validate or update TOTP state
  UsersModel-->>TOTPFunctions: return operation result
  TOTPFunctions-->>APIv1Users: return TOTP response
  APIv1Users-->>TwoFactorTOTP: return REST payload or error
Loading

Suggested labels: type: chore, area: authentication

Suggested reviewers: sampaiodiego, tassoevan, ahmed-n-abdeltwab, ricardogarim, kevlehman

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly captures the main change: migrating 2FA TOTP DDP methods to REST endpoints.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented May 29, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 57.42574% with 43 lines in your changes missing coverage. Please review.
✅ Project coverage is 68.55%. Comparing base (14d0718) to head (6cf199e).
⚠️ Report is 83 commits behind head on develop.

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop   #40734      +/-   ##
===========================================
+ Coverage    68.51%   68.55%   +0.03%     
===========================================
  Files         4124     4129       +5     
  Lines       160126   160197      +71     
  Branches     29126    29173      +47     
===========================================
+ Hits        109714   109817     +103     
+ Misses       45301    45268      -33     
- Partials      5111     5112       +1     
Flag Coverage Δ
e2e 58.97% <37.50%> (-0.04%) ⬇️
e2e-api 45.70% <61.17%> (+0.07%) ⬆️
unit 70.44% <ø> (+0.02%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All reported issues were addressed across 11 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread apps/meteor/server/lib/2fa/functions/totp.ts
Comment thread apps/meteor/client/views/account/security/TwoFactorTOTP.tsx Outdated
Comment thread apps/meteor/app/api/server/v1/users.ts Outdated

@hacktron-app hacktron-app Bot 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.

1 issue found across 1 file

Severity Count
HIGH 1

View full scan results

Comment thread apps/meteor/server/api/v1/users.ts

@sampaiodiego sampaiodiego left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

rename endpoints following our code style guide: https://developer.rocket.chat/docs/code-style-guide

I understand the idea of using "totp" as a sub-namespace, but I think it is ok having them like:

  • /v1/users.enableTotp
  • /v1/users.regenerateTotpCodes

@ggazzo
ggazzo force-pushed the chore/ddp-migrate-batch5-2fa branch from 1e5bee0 to 463826e Compare July 13, 2026 16:02
@coderabbitai coderabbitai Bot added area: authentication type: feature Pull requests that introduces new feature and removed type: chore labels Jul 13, 2026
@ggazzo
ggazzo force-pushed the chore/ddp-migrate-batch5-2fa branch from 9959f49 to af07ce6 Compare July 13, 2026 21:21
@coderabbitai coderabbitai Bot added type: chore and removed type: feature Pull requests that introduces new feature labels Jul 13, 2026
@ggazzo
ggazzo force-pushed the chore/ddp-migrate-batch5-2fa branch 2 times, most recently from 166fa4d to e4bbf4f Compare July 17, 2026 03:08
ggazzo and others added 6 commits July 17, 2026 00:18
Added five new REST endpoints under /v1/users.totp.* covering the TOTP
flows that previously only existed as DDP methods:

- POST /v1/users.totp.enable            (2fa:enable)
- POST /v1/users.totp.disable           (2fa:disable)
- POST /v1/users.totp.validate          (2fa:validateTempToken)
- POST /v1/users.totp.regenerateCodes   (2fa:regenerateCodes)
- GET  /v1/users.totp.codesRemaining    (2fa:checkCodesRemaining)

Each DDP method body was extracted into a shared function under
apps/meteor/app/2fa/server/functions/totp.ts; the DDP methods now log
deprecation pointing at the new routes and delegate.

validate keeps the post-enable login-token rotation: the REST endpoint
forwards the request's X-Auth-Token (this.token) so non-PAT tokens get
revoked just like the DDP path did via this.connection.httpHeaders.

Client TwoFactorTOTP swapped from five useMethod hooks to five
useEndpoint hooks. disable response shape changed from bare boolean to
{ disabled: boolean }; verify/regenerate continue to return { codes }.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Rename endpoints to namespace.camelCaseAction per the code style guide:
  users.totp.enable/disable/validate/regenerateCodes/codesRemaining become
  users.enableTotp/disableTotp/validateTotp/regenerateTotpCodes/totpCodesRemaining
  (routes, rest-typings, client callers, deprecation logs, changesets).
- Fix token double-hashing in users.validateTotp: pass the raw x-auth-token so
  validateTotpTempToken hashes it once, otherwise the caller's own session token
  was revoked instead of being preserved.
- Add per-user rate limiting (5/60s) to users.disableTotp, users.validateTotp and
  users.regenerateTotpCodes to prevent brute-forcing the 6-digit code.
- Show 'Invalid_two_factor_code' on invalid-totp failures in the TOTP account
  page instead of the raw endpoint error.
@ggazzo
ggazzo force-pushed the chore/ddp-migrate-batch5-2fa branch from e4bbf4f to ddc6761 Compare July 17, 2026 03:22

@hacktron-app hacktron-app Bot 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.

1 issue found across 1 file

Severity Count
HIGH 1

View full scan results

Comment thread apps/meteor/server/api/v1/users.ts
@ggazzo

ggazzo commented Jul 17, 2026

Copy link
Copy Markdown
Member Author

/jira ARCH-2166

Enrolling a new TOTP device now requires verifying existing 2FA (twoFactorRequired),
closing a bypass where a hijacked session could register an attacker-controlled TOTP
without confirming the account owner. disableTotp/regenerateTotpCodes already verify
the submitted TOTP code inline, so they keep their body-code check (no double prompt).
Adds regression tests asserting totp-required without the challenge.
@ggazzo

ggazzo commented Jul 17, 2026

Copy link
Copy Markdown
Member Author

Security: 2FA now required to enroll TOTP

Addressing the hacktron HIGH (2FA enrollment bypass): users.enableTotp and users.validateTotp now carry twoFactorRequired: true + twoFactorOptions: { disableRememberMe: true }. Enrolling a new TOTP device requires verifying the account's existing 2FA first (or the password fallback when no 2FA is active yet), so a hijacked session can no longer register an attacker-controlled TOTP.

Scope — only the enrollment pair is gated:

Endpoint 2FA gate Rationale
users.enableTotp root of the enrollment bypass
users.validateTotp activates the new method
users.disableTotp already verifies the submitted TOTP code inline — a gate would double-prompt
users.regenerateTotpCodes same — inline code verification
users.totpCodesRemaining read-only

Not a breaking change: these REST endpoints are new, and the deprecated 2fa:* DDP methods are untouched (existing DDP consumers unaffected). The web client handles the challenge automatically via the 2FA modal (handleTwoFactorChallenge).

Behavior note: during TOTP setup the web user is now prompted for their password (or existing 2FA code) — the intended step-up. All five endpoints are also rate-limited.

Added regression tests asserting totp-required when the challenge isn't satisfied, plus the password-fallback header on the happy paths. Changeset updated.

Comment thread apps/meteor/tests/end-to-end/api/users.ts Fixed
…ests challenge

A prior suite disables Accounts_TwoFactorAuthentication_Enabled globally, so the gate
was a no-op and enableTotp/validateTotp returned 200 without a challenge. Enable it (and
force the password fallback) in the TOTP describe so the regression/happy-path tests hold.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All reported issues were addressed across 1 file (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread apps/meteor/tests/end-to-end/api/users.ts Outdated
The e2e API suite runs with TEST_MODE, which bypasses twoFactorRequired (checkCodeForUser
returns early), so the totp-required regression tests can never pass and the 2FA header is
a no-op. Test the endpoint logic for a fresh user without a challenge; the gate still
protects real users with existing 2FA in production.
@ggazzo ggazzo added this to the 8.8.0 milestone Jul 24, 2026
@ggazzo ggazzo added the stat: QA assured Means it has been tested and approved by a company insider label Jul 24, 2026
@ggazzo
ggazzo merged commit 2052886 into develop Jul 24, 2026
47 of 48 checks passed
@ggazzo
ggazzo deleted the chore/ddp-migrate-batch5-2fa branch July 24, 2026 16:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: authentication stat: QA assured Means it has been tested and approved by a company insider type: chore

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants