Skip to content

Conversation

@vasusadariya
Copy link

@vasusadariya vasusadariya commented Dec 26, 2025

Proposed changes

Fixed a critical bug in the CAS authentication flow that prevented multi-factor authentication (MFA) from completing. The issue occurred when using cascaded CAS servers where the first CAS server delegates to a second CAS server for MFA.

Previously, the AuthenticationWebView would close prematurely when detecting any CAS ticket in the URL, including intermediate redirects between CAS servers. This fix adds a check to ensure the webview only closes when the authentication flow redirects back to the Rocket.Chat server itself, allowing the complete MFA flow to finish successfully.

Changes:

  • Added validation to check if the redirect URL is back to the Rocket.Chat server before closing the authentication webview
  • Prevents premature closure during CAS-to-CAS server redirects for MFA
  • Maintains backward compatibility with single-factor CAS and SAML authentication

Issue(s)

Fixes the CAS MFA authentication issue where the app closes the authentication webview before completing the second factor validation.

How to test or reproduce

Setup:

  1. Configure a Rocket.Chat server (v7.1.0+) with CAS authentication where the CAS server delegates to another CAS server for MFA (two-factor authentication)

Steps to reproduce the bug (before fix):

  1. Open the Rocket.Chat mobile app
  2. Select a server with cascaded CAS authentication
  3. Enter credentials for first-factor authentication
  4. Observe that the webview closes immediately when redirected to the second CAS server (before MFA can be completed)
  5. Authentication fails

Expected behavior (after fix):

  1. Open the Rocket.Chat mobile app
  2. Select a server with cascaded CAS authentication
  3. Enter credentials for first-factor authentication
  4. Webview remains open during redirect to second CAS server
  5. Complete MFA on the second CAS server
  6. Webview closes only after final redirect back to Rocket.Chat server
  7. Authentication succeeds

Affected screens:

  • AuthenticationWebView.tsx - CAS/SAML authentication flow

Screenshots

N/A - Authentication flow behavior (no visual UI changes)

Types of changes

  • Bugfix (non-breaking change which fixes an issue)
  • Improvement (non-breaking change which improves a current function)
  • New feature (non-breaking change which adds functionality)
  • Documentation update (if none of the other choices apply)

Checklist

  • I have read the CONTRIBUTING doc
  • I have signed the CLA
  • Lint and unit tests pass locally with my changes
  • I have added tests that prove my fix is effective or that my feature works (if applicable)
  • I have added necessary documentation (if applicable)
  • Any dependent changes have been merged and published in downstream modules

Further comments

This is a targeted fix that addresses the root cause without affecting other authentication flows. The change is minimal and adds a single conditional check to verify the redirect URL matches the Rocket.Chat server before triggering the login process.

Technical details:

  • The fix checks url.includes(server) before processing CAS/SAML tickets
  • This allows intermediate redirects between authentication servers without closing the webview
  • The webview will only close once the final redirect returns to the Rocket.Chat server domain
  • Tested scenario: First CAS server validates credentials → redirects to second CAS server for MFA (URL contains ticket but not Rocket.Chat server domain) → second CAS completes MFA → redirects back to Rocket.Chat server → webview closes and authentication completes

This fix is backward compatible and doesn't affect:

  • Single-factor CAS authentication
  • SAML authentication
  • OAuth authentication
  • iframe authentication

Summary by CodeRabbit

  • Bug Fixes
    • Improved SAML/CAS redirect handling so the auth UI only closes for redirects back to your Rocket.Chat server, and distinct identity-provider and CAS token responses are handled correctly to complete authentication.

✏️ Tip: You can customize this high-level summary in your review settings.

@CLAassistant
Copy link

CLAassistant commented Dec 26, 2025

CLA assistant check
All committers have signed the CLA.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 26, 2025

Walkthrough

Introduces a conditional guard in the authentication webview to verify SAML/CAS redirect URLs originate from the Rocket.Chat server before extracting tokens and building the payload, preventing the webview from closing on external redirects.

Changes

Cohort / File(s) Summary
SAML/CAS Redirect Validation
app/views/AuthenticationWebView.tsx
Added isRocketChatServer = url.startsWith(server) check and gated the SAML/CAS branch so token extraction and payload construction (handling saml_idp_credentialToken vs CAS token) only occur when the redirect URL matches the Rocket.Chat server.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant User
  participant WebView
  participant AppHandler as App (Auth Handler)
  participant Server as Rocket.Chat Server

  User->>WebView: Perform SSO login (SAML/CAS)
  WebView->>Server: Navigate through IdP flow
  Server-->>WebView: Redirect to callback URL (may contain ticket or saml_idp_credentialToken)
  WebView->>AppHandler: onNavigation(url)
  alt url startsWith(server) (isRocketChatServer)
    AppHandler->>AppHandler: validate URL and extract token (ticket or saml_idp_credentialToken)
    alt saml_idp_credentialToken present
      AppHandler->>AppHandler: build payload { credentialToken, saml: true }
    else CAS token path
      AppHandler->>AppHandler: build payload { cas: { credentialToken: ssoToken } }
    end
    AppHandler->>Server: submit authentication payload
    AppHandler->>WebView: close()
  else external redirect (not Rocket.Chat server)
    AppHandler->>WebView: ignore / keep webview open
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I peeked at redirects, soft and bright,
I only let Rocket.Chat hop into sight,
Tokens gathered where the server meets,
I close the door on wandering streets,
Securely hopping home tonight. 🥕✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main fix: preventing premature webview closure during delegated CAS authentication by validating the redirect URL origin.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 536537d and 3a6f767.

📒 Files selected for processing (1)
  • app/views/AuthenticationWebView.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/views/AuthenticationWebView.tsx

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 and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/views/AuthenticationWebView.tsx (1)

112-121: Declare the payload variable before use.

The variable payload is assigned at lines 115 and 117 but never declared, causing a TypeScript compilation error with strict mode enabled. Add let payload; before the conditional at line 112.

Additionally, while the isRocketChatServer guard correctly prevents premature webview closure during CAS delegation, ensure the SAML vs CAS payload distinction is tested with both single-factor and delegated authentication flows.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 0d13c14 and 536537d.

📒 Files selected for processing (1)
  • app/views/AuthenticationWebView.tsx
🧰 Additional context used
🧬 Code graph analysis (1)
app/views/AuthenticationWebView.tsx (1)
app/sagas/login.js (4)
  • server (86-86)
  • server (230-230)
  • server (299-299)
  • server (375-375)

@vasusadariya
Copy link
Author

vasusadariya commented Dec 27, 2025

Hey
i have just raise a PR #6833 issue that completely fixes this issue so please check it out and go through it!!
Tell me if i can add on anything else to my solution

@floriannari
Copy link

floriannari commented Jan 6, 2026

Hello, and thank you for this PR.
As it stands, it doesn't work, but with a slight modification, it fixes the issue #6833 :

		if (authType === 'saml' || authType === 'cas') {
			const parsedUrl = parse(url, true);
			// Only close the webview when redirected back to the Rocket.Chat server
			// This prevents premature closure when CAS delegates to another CAS server for MFA
			const isRocketChatServer = url.startsWith(server);
			// ticket -> cas / validate & saml_idp_credentialToken -> saml
			if (isRocketChatServer && (parsedUrl.pathname?.includes('validate') || parsedUrl.query?.ticket || parsedUrl.query?.saml_idp_credentialToken)) {
				let payload: ICredentials;
				if (authType === 'saml') {
					const token = parsedUrl.query?.saml_idp_credentialToken || ssoToken;
					const credentialToken = { credentialToken: token };
					payload = { ...credentialToken, saml: true };
				} else {
					payload = { cas: { credentialToken: ssoToken } };
				}
				debouncedLogin(payload);
			}
		}

We hope that this will be quickly incorporated into a future update of the mobile application 🙏

@diegolmello
Copy link
Member

@vasusadariya can you add @floriannari changes?

@vasusadariya
Copy link
Author

hey @diegolmello thanks! i will add these changes that @floriannari suggest me

@vasusadariya
Copy link
Author

hey @diegolmello i have added all the changes that @floriannari has suggested so please go through it and if all good then you can merge it!

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.

4 participants