RocketChat / RocketChat/Rocket.Chat

2FA verification broken for SAML SSO login (v8.5.1)

Open
#41,394 3 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

type: bug
Dominant language
TypeScript
Stars
46.1k
Forks
13.9k
Avg merge
3d 3h
Merged PRs (30d)
130

Description

Description:

2FA verification is broken specifically for SAML SSO login. When the SAML login flow issues a 2FA challenge (TOTP, or Email with a verified address), the follow-up login call containing the code is rejected every time — 2FA-enabled users can never complete SSO login. Separately, if the user's email address is unverified, the Email 2FA challenge is skipped entirely during SAML login, silently bypassing the org's 2FA policy for that account. The same TOTP/email codes are verified correctly via username/password login and via account Security settings, which isolates the defect to the SAML method.callAnon/login handshake.

Steps to reproduce:
  1. On a SAML-linked user account with a verified email address, enable TOTP (2fa:enable → scan QR → 2fa:validateTempToken confirms success) or Email 2FA (users.2fa.enableEmail)
  2. Log out; open a fresh incognito window
  3. Initiate SSO login via the SAML button, authenticate at the IdP normally
  4. First method.callAnon/login call (~139 bytes) returns 400 (2FA required — correct so far). For email 2FA, users.2fa.sendEmailCode fires and a code arrives normally
  5. Enter the current, valid code (TOTP from the app, or the freshly emailed code) and submit
  6. The resubmitted method.callAnon/login call (~182-183 bytes, code appended) returns 400 again — code rejected
  7. Request a brand-new code and resubmit on the same credentialToken — still rejected
  8. Repeat from step 3 with a brand-new SAML round-trip and a freshly generated valid code — identical result every time
  9. Separately: repeat steps 2-3 on a SAML-linked account that has Email 2FA enabled but an unverified email address — login succeeds in a single round-trip with no 2FA challenge issued at all
Expected behavior:

Users with personal 2FA enabled (TOTP or Email) should be challenged for their 2FA code during SAML SSO login, consistent with password-login behavior, and a valid, correctly-entered code should be accepted and complete the login.

Actual behavior:

When a 2FA challenge is issued during SAML login (TOTP, or Email with a verified address), the code-verification step unconditionally rejects every submission, permanently blocking SSO login for any 2FA-enabled user (reproduced across ~25 attempts on 2 independent accounts, 0 successes). Separately, Email 2FA is silently skipped (no challenge issued, no code emailed) when the account's email address is unverified — currently true for 15 active SAML-linked, email-2FA-enabled accounts on this workspace, one of which (masked as "Account X") was independently observed exhibiting this exact bypass prior to any deliberate testing.

Server Setup Information:
  • Version of Rocket.Chat Server: 8.5.1
  • License Type: Community (no Enterprise license applied)
  • Number of Users: 148 total / 86 active
  • Operating System: Ubuntu 26.04 LTS
  • Deployment Method: docker (Docker Compose)
  • Number of Running Instances: 1
  • DB Replicaset Oplog: rs0
  • NodeJS Version: v22.22.3
  • MongoDB Version: 8.0.26
Client Setup Information:
  • Desktop App or Browser Version: reproduced on both Rocket.Chat Desktop 4.14.1 (Electron 40.8.5) and Chrome 150 (browser)
  • Operating System: reproduced on Windows 11 and macOS
Additional context:
  • Reverse proxy is Traefik, forwarding X-Forwarded-For/X-Forwarded-Proto correctly — confirmed not a factor via log inspection.
  • SAML IdP is ADFS, IdP-initiated flow.
  • Relevant settings: Accounts_TwoFactorAuthentication_Enabled: true, Accounts_TwoFactorAuthentication_By_Email_Enabled: true, Accounts_TwoFactorAuthentication_By_TOTP_Enabled: true, Accounts_TwoFactorAuthentication_Enforce_Password_Fallback: true, Accounts_TwoFactorAuthentication_RememberFor: 1800, Accounts_twoFactorAuthentication_email_available_for_OAuth_users: true.
  • Workaround: affected users can log in with username/password + 2FA (works correctly) instead of the SSO button. No known workaround exists to make SSO + 2FA succeed together; disabling personal 2FA restores one-step SSO login but removes 2FA protection entirely.
  • Comparison data ruling out 2FA-in-general being broken:
Context Result
SAML SSO login (2nd step, code resubmission) — TOTP Rejected, 100% of attempts
SAML SSO login (2nd step, code resubmission) — Email Rejected, 100% of attempts
Username/password login + TOTP challenge Accepted normally
Disabling TOTP via Account → Security (requires current TOTP code) Accepted normally
users.2fa.sendEmailCode itself Sends successfully, email delivered normally
Relevant logs:

Working password-login + 2FA sequence, for reference (payload grows once the code is appended, and the second call succeeds):

method.callAnon/login  244 bytes -> 400  (2FA required)
method.callAnon/login  288 bytes -> 200  (code accepted, login succeeds)

Broken SAML-login + 2FA sequence (payload grows the same way, but the second call never succeeds, even across repeated retries and brand-new SAML round-trips):

method.callAnon/login  139 bytes -> 400  (2FA required)
method.callAnon/login  182 bytes -> 400  (code rejected)
method.callAnon/login  182 bytes -> 400  (code rejected, retried)

Secondary defect — unverified email silently skipping the challenge:

method.callAnon/login  139 bytes -> 200  (login succeeds immediately, no 2FA challenge, email unverified)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by tracing the SAML method.callAnon/login handshake and compare its two-step 2FA flow with the working username/password login flow. Check the handling of TOTP, email codes, credentialToken, and unverified email under the listed 2FA settings. Done means valid TOTP and email codes complete SAML login, while unverified email accounts still receive the required challenge; add or run coverage for both defects.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
authentication, backend, security
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.