Fix SAML cancel leaving sign-in page without email field#88760
Conversation
When a SAML-required user closes the browser without completing login, the cancel and error paths now call clearSignInData() before navigating back, matching the existing back button behavior. This ensures SignInPage correctly shows the email field instead of a blank page. Co-authored-by: Vinh Hoang <hoangzinh@users.noreply.github.com>
Codecov Report✅ Changes either increased or maintained existing code coverage, great job!
|
|
@MelvinBot make this PR ready |
|
@MelvinBot copy this into QA tests Precondition: SAML requirement for login is enabled on OD.
|
|
@MelvinBot can you check off all PR author Checklist. I will ensure to all of them are checked |
|
🤖 I've updated the PR body with the test steps:
Please mark this PR as "Ready for review" when you're ready — I wasn't able to do it automatically. |
|
🤖 Done — all PR Author Checklist items are now checked off. |
|
@MelvinBot please mark this PR ready for review |
|
🤖 Done! This PR has been marked as ready for review. |
|
@hoangzinh Please copy/paste the Reviewer Checklist from here into a new comment on this PR and complete it. If you have the K2 extension, you can simply click: [this button] |
| .then((response: WebBrowserAuthSessionResult) => { | ||
| if (response.type !== 'success') { | ||
| Navigation.goBack(); | ||
| clearSignInData(); |
There was a problem hiding this comment.
❌ CONSISTENCY-3 (docs)
The clearSignInData() + Navigation.isNavigationReady().then(() => Navigation.goBack()) block is duplicated three times in this file: in the cancel path (response.type !== 'success'), in the .catch handler, and in the onBackButtonPress callback. This increases maintenance overhead -- if the cleanup logic changes, all three sites must be updated.
Extract a helper function to eliminate the duplication:
const handleExitSAMLFlow = useCallback(() => {
clearSignInData();
Navigation.isNavigationReady().then(() => {
Navigation.goBack();
});
}, []);Then use handleExitSAMLFlow() in all three locations (cancel path, catch handler, and onBackButtonPress).
Reviewed at: 0b70b7b | Please rate this suggestion with 👍 or 👎 to help us improve! Reactions are used to monitor reviewer efficiency.
There was a problem hiding this comment.
@MelvinBot what do you think about this feedback?
There was a problem hiding this comment.
The suggestion is valid. The clearSignInData() + Navigation.isNavigationReady().then(() => Navigation.goBack()) block is identical in all three places (cancel path, catch handler, and onBackButtonPress). Extracting a handleExitSAMLFlow callback would reduce duplication with no behavioral change.
Note: the pattern in handleNavigationStateChange (line 63-69) is intentionally different — it also calls setAccountError and navigates to ROUTES.HOME, so it should NOT be folded in.
Want me to implement this refactor?
There was a problem hiding this comment.
Done — extracted a handleExitSAMLFlow callback that's now used in all three places (cancel path, catch handler, and back button press).
|
@MelvinBot I faced the same bug in web Screen.Recording.2026-04-27.at.14.22.38.mov |
When a SAML-required user browser-backs from the IdP on web, credentials.login is still set in Onyx but clearSignInData() is async. This caused a blank SignInPage with no form visible until the Onyx update propagated. Now shouldShowLoginForm is true immediately when the SAML-reload guard fires. Co-authored-by: Vinh Hoang <hoangzinh@users.noreply.github.com>
|
🤖 Pushed a fix for the web SAML cancel bug. Root cause: When a SAML-required user browser-backs from the IdP on web, Fix: |
|
🤖 This PR is already fully set up:
If there's something specific you'd like me to implement, please let me know what it is! |
Extract the repeated clearSignInData() + Navigation.isNavigationReady().then(goBack) pattern into a single handleExitSAMLFlow useCallback, used by the cancel path, catch handler, and back button press. Co-authored-by: Vinh Hoang <hoangzinh@users.noreply.github.com>
joekaufmanexpensify
left a comment
There was a problem hiding this comment.
Gotta make sure we keep that email field to sign in! 😄
@MelvinBot it seems doesn't work to me on web |
On web, SAMLSignInPage uses window.location.replace() to redirect to the IdP, which causes a full page reload on browser-back. The React state hasInitiatedSAMLLogin resets to false, and depending on account.isLoading during Onyx hydration, shouldInitiateSAMLLogin may fire again (re-redirecting to IdP) before isClearingSAMLSignInData gets a chance to clear credentials. Fix: use sessionStorage to persist the SAML initiation flag across page reloads. SignInPage reads and clears this flag on mount, preventing re-initiation and forcing the sign-in data clear path regardless of account.isLoading timing. Co-authored-by: Vinh Hoang <hoangzinh@users.noreply.github.com>
|
🤖 Pushed a fix for the web SAML cancel issue. Root cause: On web, Fix: Use |
|
@MelvinBot can you revert those commits I tested on a wrong account |
|
🤖 Reverted both commits as requested:
|
Reviewer Checklist
Screenshots/VideosAndroid: HybridAppScreen.Recording.2026-04-28.at.17.14.21.movAndroid: mWeb ChromeScreen.Recording.2026-04-28.at.18.17.07.moviOS: HybridAppScreen.Recording.2026-04-28.at.20.16.50.moviOS: mWeb SafariScreen.Recording.2026-04-28.at.20.18.03.movMacOS: Chrome / SafariScreen.Recording.2026-04-28.at.18.13.09.mov |
|
@grgia all yours |
|
✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release. |
|
🚧 @grgia has triggered a test Expensify/App build. You can view the workflow run here. |
|
🧪🧪 Use the links below to test this adhoc build on Android, iOS, and Web. Happy testing! 🧪🧪
|
|
🚀 Deployed to staging by https://github.com/grgia in version: 9.3.65-0 🚀
Bundle Size Analysis (Sentry): |
|
No help site changes required. This PR fixes an internal app navigation bug (blank screen after canceling the SAML browser on native). The existing SAML help articles (Set-Up-SAML-SSO, Troubleshoot-SAML-SSO-Login) cover server-side configuration and error messages — none of that is affected by this code change. |
Explanation of Change
When a SAML-required user closes the browser without completing login, the app navigates back to SignInPage but shows only the background animation with no email field. This happens because the cancel and error paths in
SAMLSignInPage/index.native.tsxcallNavigation.goBack()without first clearing sign-in data, leavingcredentials.loginset and preventing any form from rendering.This fix adds
clearSignInData()beforeNavigation.goBack()in both the cancel path (response.type !== 'success') and the.catchhandler, matching the existing back button and error handler patterns already in the same file. Also wrapsNavigation.goBack()inNavigation.isNavigationReady().then()for consistency with those same patterns.Fixed Issues
$ #88206
PROPOSAL: #88206 (comment)
Tests
Precondition: SAML requirement for login is enabled on OD.
Offline tests
N/A - This fix addresses SAML sign-in browser cancellation, which requires an active network connection to initiate.
QA Steps
Precondition: SAML requirement for login is enabled on OD.
PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectiontoggleReportand notonIconClick)src/languages/*files and using the translation methodSTYLE.md) were followedAvatar, I verified the components usingAvatarare working as expected)StyleUtils.getBackgroundAndBorderStyle(theme.componentBG))npm run compress-svg)Avataris modified, I verified thatAvataris working as expected in all cases)Designlabel and/or tagged@Expensify/designso the design team can review the changes.ScrollViewcomponent to make it scrollable when more elements are added to the page.mainbranch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTeststeps.Screenshots/Videos
Android: Native
Android: mWeb Chrome
iOS: Native
iOS: mWeb Safari
MacOS: Chrome / Safari