Skip to content

Conversation

@praneeth622
Copy link

@praneeth622 praneeth622 commented Aug 31, 2025

Closes #2993

🎯 Problem Solved

The desktop app was showing authentication popups in isolated Electron windows that don't have access to:

  • Saved passwords from password managers
  • Browser-stored passkeys for MFA/SSO
  • Biometric authentication (TouchID, Windows Hello)
  • Browser extensions for security

This was particularly problematic for users with SSO setups requiring passkeys, as mentioned in the issue - they couldn't log in at all. Additionally, users with custom/in-house OAuth providers (like on-premise BitWarden) couldn't authenticate properly.

🔧 Solution Implemented

Added intelligent authentication detection that redirects OAuth/SSO login flows to the user's default browser instead of creating isolated Electron popups.

Key Features:

  • 🎯 Robust OAuth Detection: Uses stricter logic requiring both client identifiers (client_id/redirect_uri) AND flow parameters (response_type/state/scope/etc.) to avoid false positives
  • 🏢 Custom Provider Support: Works with in-house OAuth solutions, BitWarden, and any custom SSO implementation
  • 🔍 Smart Detection: Recognizes authentication flows by frame names (Login, OAuth, SSO), URL patterns, and known provider domains
  • 🌐 Provider Support: Works with Google, Microsoft, GitHub, GitLab, Okta, Auth0, and other major providers
  • ⬅️ Backward Compatibility: Video calls and other legitimate popups continue to work as before
  • 🛡️ Error Handling: Robust URL parsing with graceful fallbacks

Technical Implementation:

  • Enhanced isAuthenticationPopup() function with multi-layered detection:
    1. Highest Priority: Stricter OAuth parameter detection requiring meaningful combinations
    2. SAML Support: Detects SAMLRequest/SAMLResponse parameters
    3. Frame name checking: Explicit authentication indicators
    4. Keyword matching: Authentication-related URL patterns
    5. Provider domains: Known authentication service domains
  • Modified setWindowOpenHandler to redirect auth popups to default browser
  • Updated did-create-window listener to handle fallback scenarios
  • Maintained existing security protocols and permission handling

📊 Enhanced Detection Logic:

🔒 OAuth Parameter Detection (Stricter Logic)

  • Client Identifiers: client_id, redirect_uri
  • Flow Parameters: response_type, state, scope, code_challenge, nonce
  • SAML Parameters: SAMLRequest, SAMLResponse

Logic: Requires both a client identifier AND a flow parameter, or any SAML parameter (definitive indicators). This prevents false positives from single parameters like state=california.

🎯 Detection Priority (Top to Bottom):

  1. SAML Authentication → SAMLRequest/SAMLResponse (definitive)
  2. OAuth Parameters → Client identifier + Flow parameter (robust)
  3. Frame NamesLogin, OAuth, SSO frame names
  4. URL Keywordsoauth, auth, login, signin, sso, authenticate
  5. Known Domains → Google, Microsoft, GitHub, etc.

Testing

  • Build: Successful (npm run build)
  • Linting: Clean (npm run lint)
  • TypeScript: No errors (tsc --noEmit)
  • Tests: All tests pass (npm test)
  • No Regressions: Video calls and other features work normally
  • OAuth Compatibility: Supports both well-known and custom OAuth providers
  • False Positive Prevention: Stricter parameter logic prevents incorrect detections

🚀 Benefits

Before:

  • Users forced to manually enter credentials in isolated popup
  • Custom OAuth providers not detected
  • No access to saved passkeys/biometric auth
  • False positives from overly broad detection

After:

  • Seamless authentication using saved browser credentials and passkeys
  • Support for any OAuth provider (custom or well-known)
  • Universal compatibility with password managers and security tools
  • Robust detection logic prevents false redirects

🙏 Acknowledgments

Special thanks to @sdlth for the valuable feedback that led to the OAuth parameter detection enhancement and the stricter logic implementation to prevent false positives!

This change significantly improves the user experience while maintaining security and compatibility with existing features.

Summary by CodeRabbit

  • New Features
    • Authentication popups (e.g., SSO/OAuth) are now automatically opened in your default browser for a smoother, more reliable sign-in experience.
  • Bug Fixes
    • Prevents blank or stuck in-app login popups by redirecting detected auth flows to the system browser.
  • Chores
    • Tightened media permission handling: media access is now denied by default unless explicitly granted, improving privacy.

praneeth622 and others added 3 commits August 29, 2025 21:43
Resolves RocketChat#2993

- Add isAuthenticationPopup() helper to detect login/OAuth/SSO popups
- Redirect authentication flows to default browser instead of Electron popup
- Allow users to access saved credentials and passkeys from their browser
- Support major OAuth providers (Google, Microsoft, GitHub, GitLab, etc.)
- Maintain compatibility with existing video call and other popup flows

This change improves user experience by leveraging browser-saved
credentials and enables passkey authentication that was previously
blocked in Electron popups.
- Add complete isAuthenticationPopup function definition
- Fix broken code structure from manual edits
- Ensure all function calls have proper scope and variables
- Maintain clean switch statement structure in permission handler
feat/default-browser-auth
@CLAassistant
Copy link

CLAassistant commented Aug 31, 2025

CLA assistant check
All committers have signed the CLA.

- Require both client identifier (client_id/redirect_uri) AND flow parameter
- Prevents false positives from single parameters like 'state=california'
- Maintains support for SAML flows with SAMLRequest/SAMLResponse
- Addresses maintainer feedback for more robust authentication detection
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 2, 2025

Walkthrough

Implements detection of authentication-related popups and redirects them to the system browser in window-open and did-create-window flows. Adds URL/frame/disposition analysis, handles protocol permission checks, and updates media permission default to deny.

Changes

Cohort / File(s) Summary of Changes
Auth popup routing & permissions
src/ui/main/serverView/index.ts
Added isAuthenticationPopup(url, frameName, disposition) to identify auth flows (SAML/OAuth/SSO/login keywords/domains). Integrated into webview new-window and did-create-window handlers to open externally and suppress Electron popups. Adjusted media permission default callback to false. Minor auth-path handling tweaks.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant WV as WebView
  participant SV as ServerView Logic
  participant D as Default Browser

  rect rgba(200,230,255,0.25)
  note over WV,SV: window.open handler
  WV->>SV: Request to open URL (url, frameName, disposition)
  SV->>SV: isAuthenticationPopup(url, frameName, disposition)?
  alt Auth popup detected
    SV->>SV: Check protocol permission
    alt Allowed
      SV->>D: openExternal(url)
      SV-->>WV: deny Electron popup
    else Not allowed
      SV-->>WV: proceed with normal handling
    end
  else Not auth popup
    SV-->>WV: proceed with normal handling
  end
  end

  rect rgba(220,255,220,0.25)
  note over SV,D: did-create-window flow
  SV->>SV: isAuthenticationPopup(newWindow.url,... )?
  alt Auth popup detected
    SV->>SV: destroy popup window
    SV->>D: openExternal(url)
  else Not auth popup
    SV->>SV: keep popup window
  end
  end

  rect rgba(255,240,200,0.25)
  note over SV: Permission handling
  SV->>SV: media permission default = false (deny)
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

A hop, a skip—no tiny panes tonight,
I nose the link and launch it into light.
SSO and OAuth, to the big wide air—
Default browser waiting, passwords there.
Carrot-click! Popups fade from view—
Secure little bunny, signing in anew. 🥕✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Out of Scope Changes Check ⚠️ Warning The change to default media permission handling by denying access by default is unrelated to the authentication popup redirection goals outlined in issue #2993 and introduces behavior outside the scope of the linked issue’s requirements. Separate the media permission default change into its own pull request or provide rationale and testing coverage for that change to ensure it aligns with project goals.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title succinctly describes the main feature change by indicating that authentication popups will be redirected to the default browser without extraneous detail, so it accurately reflects the primary purpose of the pull request.
Linked Issues Check ✅ Passed The implementation enhances popup detection logic and integrates redirection of OAuth and SSO login flows to the default browser as described in issue #2993, satisfying the primary objective to leverage browser-managed authentication for improved sign-in reliability.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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: 0

Caution

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

⚠️ Outside diff range comments (2)
src/ui/main/serverView/index.ts (2)

417-431: Critical: Media access broken on Windows and Linux.

The change at line 430 from callback(true) to callback(false) denies all media permissions on non-macOS platforms by default. This will break video calls, voice messages, and any feature requiring camera or microphone access on Windows and Linux.

This appears to be an unintended change that breaks core functionality. Please verify:

  1. Was this change intentional?
  2. If so, what is the reasoning for blocking media access on Windows/Linux?
  3. If not, this should be reverted.

Apply this diff to restore media access on Windows/Linux:

-        callback(false);
+        callback(true);
         return;
       }

If there's a security concern that motivated this change, consider implementing proper permission prompts for Windows/Linux similar to the macOS flow, rather than blocking all media access.


380-391: Remove dead Google Sign-In userAgent override.
Since isAuthenticationPopup already redirects any window with frameName === 'Login', the isGoogleSignIn branch (lines 388–391) never executes. Remove that block and the associated userAgent override.

🧹 Nitpick comments (1)
src/ui/main/serverView/index.ts (1)

119-135: Simplify domain pattern matching for known auth providers.

The regex patterns for authentication providers (lines 120-131) all follow the same subdomain pattern ^([a-z0-9-]+\.)*domain\.tld$. This is more complex than needed and could be simplified.

Consider simplifying the domain checks:

-      const authProviders = [
-        /^([a-z0-9-]+\.)*google\.com$/,
-        /^([a-z0-9-]+\.)*microsoft\.com$/,
-        /^([a-z0-9-]+\.)*microsoftonline\.com$/,
-        /^([a-z0-9-]+\.)*facebook\.com$/,
-        /^([a-z0-9-]+\.)*github\.com$/,
-        /^([a-z0-9-]+\.)*gitlab\.com$/,
-        /^([a-z0-9-]+\.)*okta\.com$/,
-        /^([a-z0-9-]+\.)*auth0\.com$/,
-        /^([a-z0-9-]+\.)*saml\.com$/,
-        /^([a-z0-9-]+\.)*onelogin\.com$/,
-      ];
-
-      if (authProviders.some((pattern) => parsedUrl.hostname.match(pattern))) {
-        return true;
-      }
+      const authProviderDomains = [
+        'google.com',
+        'microsoft.com',
+        'microsoftonline.com',
+        'facebook.com',
+        'github.com',
+        'gitlab.com',
+        'okta.com',
+        'auth0.com',
+        'saml.com',
+        'onelogin.com',
+      ];
+
+      if (authProviderDomains.some((domain) => 
+        parsedUrl.hostname === domain || parsedUrl.hostname.endsWith('.' + domain)
+      )) {
+        return true;
+      }

This approach is clearer, easier to maintain, and has the same matching behavior.

📜 Review details

Configuration used: CodeRabbit 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 9a7fb81 and 668cc28.

📒 Files selected for processing (1)
  • src/ui/main/serverView/index.ts (4 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Follow existing TypeScript patterns with strict mode enabled
All new code must pass ESLint and TypeScript checks
Avoid unnecessary comments; only add comments for complex logic or non-obvious decisions

Files:

  • src/ui/main/serverView/index.ts
🧬 Code graph analysis (1)
src/ui/main/serverView/index.ts (2)
src/navigation/main.ts (1)
  • isProtocolAllowed (213-241)
src/utils/browserLauncher.ts (1)
  • openExternal (58-90)
🔇 Additional comments (2)
src/ui/main/serverView/index.ts (2)

334-347: LGTM! Clean authentication popup handling in window open handler.

The integration correctly:

  • Detects authentication popups before allowing standard popup creation
  • Checks protocol permissions before opening externally
  • Handles errors gracefully without crashing
  • Returns { action: 'deny' } to prevent the Electron popup from being created

The promise chain with .then().catch() is appropriate here since the function returns synchronously.


103-117: Restrict auth keyword matching to pathname and search
Matching generic terms (e.g., “auth”, “login”) anywhere in the URL can flag benign popups (e.g., /unauthorized-error). Instead use parsedUrl.pathname + parsedUrl.search with path-segment prefixes (e.g., '/auth', '/login') or word boundaries.

@sdlth
Copy link

sdlth commented Oct 21, 2025

Hello,
Could someone at Rocket.Chat.Electron take a look at this ?
At the moment, our organization is migrating towards FIDO2 keys and, since a lot of our users have this client, having that kind of fix would allow us to force IT in a FIDO2-only scenario and get to the security levels we are aiming for.

I don't have the skills to say if the code is clean enough, if the edge cases are taken into account, or anything of the sort. I'm just here to highlight #2993 and our need for it to be fixed.
It would really help a lot.
Cheers.

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.

Sign in with the default browser instead of a popup

3 participants