Description
On Android, advanced authentication (browser Custom Tab) relies on appending &prompt=login to the authorize URL "to prevent the browser cookie from bypassing login if it exists" (LoginActivity.buildCustomTabAuthorizeUrl). For orgs whose My Domain is federated to an external IdP via SAML 2.0 / WS-Fed (e.g. Microsoft Entra), prompt=login on the Salesforce authorize URL is not propagated to the external IdP as a forced re-authentication. The IdP's persistent browser SSO session therefore silently re-authenticates the previously signed-in user.
Impact: on shared devices (e.g. retail store tablets shared by staff), a user cannot switch to or add a different account. switchToNewUser() opens the Custom Tab, the IdP session re-asserts the previous user, and the app returns to that same user — getAuthenticatedUsers() never changes. This makes multi-user / shared-device usage unworkable on federated orgs.
The iOS SDK avoids this by running the advanced-auth browser session ephemerally by default (SalesforceSDKManager.useEphemeralSessionForAdvancedAuth = YES → ASWebAuthenticationSession.prefersEphemeralWebBrowserSession = YES), so no persistent IdP session is ever visible to reuse — regardless of federation. The Android SDK has no equivalent option.
Root Cause
Android's only mechanism to avoid session reuse is the prompt=login query parameter, appended in LoginActivity.buildCustomTabAuthorizeUrl (libs/SalesforceSDK/src/com/salesforce/androidsdk/ui/LoginActivity.kt):
val urlWithSdkInfo = "$loginUrl&sdkInfo=$sdkInfo&auth_trigger=$authTrigger"
return if (sharedBrowserSession) urlWithSdkInfo else urlWithSdkInfo + PROMPT_LOGIN
// private const val PROMPT_LOGIN = "&prompt=login"
prompt=login is honored at the Salesforce /authorize endpoint, but for a My Domain federated via SAML/WS-Fed, Salesforce does not translate it into ForceAuthn on the AuthnRequest to the external IdP. The external IdP's live browser session is therefore reused, and the same user is silently re-asserted.
The Custom Tab itself is built without an isolated/ephemeral session in LoginActivity.loadLoginPageInCustomTab:
val customTabsIntent = CustomTabsIntent.Builder().apply {
...
setShareState(CustomTabsIntent.SHARE_STATE_OFF)
...
// no ephemeral / cookie-isolated session
}.build()
By contrast, iOS (SFOAuthCoordinator.m) applies an ephemeral session that is on by default (SalesforceSDKManager.m: self.useEphemeralSessionForAdvancedAuth = YES;):
_asWebAuthenticationSession.prefersEphemeralWebBrowserSession =
[SalesforceSDKManager sharedManager].useEphemeralSessionForAdvancedAuth;
Steps to Reproduce
- Configure an org whose My Domain is federated to an external IdP via SAML 2.0 (e.g. Microsoft Entra), with the IdP keeping a persistent browser session ("stay signed in").
- On an Android device, sign in as User A via advanced auth (Custom Tab).
- Call
UserAccountManager.switchToNewUser() (or use the account switcher's "add new user").
- At the IdP, the persistent session silently re-authenticates User A — no account chooser is shown.
- Observe: the app returns to User A;
getAuthenticatedUsers() still contains only User A. Switching to a different user is impossible without manually clearing the external browser's cookies (which the app cannot do).
Expected Behavior
The advanced-auth browser session should be able to run ephemerally (cookie-isolated), matching iOS, so that a persistent external-IdP session cannot silently bypass account selection. This would let users switch/add accounts on shared devices regardless of federation.
Suggested Fix
androidx.browser 1.8.0+ exposes CustomTabsIntent.Builder.setEphemeralBrowsingEnabled(true) (honored by Chrome 136+, feature-detectable via CustomTabsClient.isEphemeralBrowsingSupported()). Add an ephemeral option on SalesforceSDKManager (mirroring iOS useEphemeralSessionForAdvancedAuth) and apply it in loadLoginPageInCustomTab:
// SalesforceSDKManager.kt — mirrors iOS useEphemeralSessionForAdvancedAuth
var useEphemeralSessionForAdvancedAuth = true
// LoginActivity.loadLoginPageInCustomTab
val customTabsIntent = CustomTabsIntent.Builder().apply {
...
if (SalesforceSDKManager.getInstance().useEphemeralSessionForAdvancedAuth) {
setEphemeralBrowsingEnabled(true)
}
}.build()
We have verified this one-line change resolves shared-device user switching on a SAML/Entra-federated org (Chrome 136+).
Open question: on iOS this is on by default — is there a reason it isn't the Android default? If default-on is undesirable on Android (e.g. because ephemeral browsing is browser-version dependent and disables autofill of saved credentials), exposing it as an opt-in setter would still close the parity gap.
Affected Versions
- Confirmed on 14.0.0-rc.2 (the
prompt=login mechanism is also present in rc.0/rc.1).
- Affects orgs federated to an external IdP via SAML 2.0 / WS-Fed, on shared / multi-user devices.
Environment
- Android SDK 14.0.0-rc.2
- Advanced authentication (browser Custom Tab, web-server + PKCE)
- My Domain federated to Microsoft Entra via SAML 2.0
- Custom Tab served by Chrome 136+ (where ephemeral browsing is available)
Description
On Android, advanced authentication (browser Custom Tab) relies on appending
&prompt=loginto the authorize URL "to prevent the browser cookie from bypassing login if it exists" (LoginActivity.buildCustomTabAuthorizeUrl). For orgs whose My Domain is federated to an external IdP via SAML 2.0 / WS-Fed (e.g. Microsoft Entra),prompt=loginon the Salesforce authorize URL is not propagated to the external IdP as a forced re-authentication. The IdP's persistent browser SSO session therefore silently re-authenticates the previously signed-in user.Impact: on shared devices (e.g. retail store tablets shared by staff), a user cannot switch to or add a different account.
switchToNewUser()opens the Custom Tab, the IdP session re-asserts the previous user, and the app returns to that same user —getAuthenticatedUsers()never changes. This makes multi-user / shared-device usage unworkable on federated orgs.The iOS SDK avoids this by running the advanced-auth browser session ephemerally by default (
SalesforceSDKManager.useEphemeralSessionForAdvancedAuth = YES→ASWebAuthenticationSession.prefersEphemeralWebBrowserSession = YES), so no persistent IdP session is ever visible to reuse — regardless of federation. The Android SDK has no equivalent option.Root Cause
Android's only mechanism to avoid session reuse is the
prompt=loginquery parameter, appended inLoginActivity.buildCustomTabAuthorizeUrl(libs/SalesforceSDK/src/com/salesforce/androidsdk/ui/LoginActivity.kt):prompt=loginis honored at the Salesforce/authorizeendpoint, but for a My Domain federated via SAML/WS-Fed, Salesforce does not translate it intoForceAuthnon the AuthnRequest to the external IdP. The external IdP's live browser session is therefore reused, and the same user is silently re-asserted.The Custom Tab itself is built without an isolated/ephemeral session in
LoginActivity.loadLoginPageInCustomTab:By contrast, iOS (
SFOAuthCoordinator.m) applies an ephemeral session that is on by default (SalesforceSDKManager.m:self.useEphemeralSessionForAdvancedAuth = YES;):_asWebAuthenticationSession.prefersEphemeralWebBrowserSession = [SalesforceSDKManager sharedManager].useEphemeralSessionForAdvancedAuth;Steps to Reproduce
UserAccountManager.switchToNewUser()(or use the account switcher's "add new user").getAuthenticatedUsers()still contains only User A. Switching to a different user is impossible without manually clearing the external browser's cookies (which the app cannot do).Expected Behavior
The advanced-auth browser session should be able to run ephemerally (cookie-isolated), matching iOS, so that a persistent external-IdP session cannot silently bypass account selection. This would let users switch/add accounts on shared devices regardless of federation.
Suggested Fix
androidx.browser1.8.0+ exposesCustomTabsIntent.Builder.setEphemeralBrowsingEnabled(true)(honored by Chrome 136+, feature-detectable viaCustomTabsClient.isEphemeralBrowsingSupported()). Add an ephemeral option onSalesforceSDKManager(mirroring iOSuseEphemeralSessionForAdvancedAuth) and apply it inloadLoginPageInCustomTab:We have verified this one-line change resolves shared-device user switching on a SAML/Entra-federated org (Chrome 136+).
Open question: on iOS this is on by default — is there a reason it isn't the Android default? If default-on is undesirable on Android (e.g. because ephemeral browsing is browser-version dependent and disables autofill of saved credentials), exposing it as an opt-in setter would still close the parity gap.
Affected Versions
prompt=loginmechanism is also present in rc.0/rc.1).Environment