The acquireToken method doesn't work if you uses "withFragmemt"
See original GitHub issueDetails We are going to make b2c authorization in our Android app and we faced with issue with “IMultipleAccountPublicClientApplication.acquireToken” method and fragment.
Smartphone (please complete the following information):
- Device: Samsun M51
- Android Version: 12,
- MSAL Version: 4.0.5
Config
{ "broker_redirect_uri_registered": false, "client_id" : "****", "authorization_user_agent" : "WEBVIEW", "redirect_uri" : "****", "authorities" : [ { "type": "B2C", "authority_url": "https://schcoad.b2clogin.com/schcoad.onmicrosoft.com/.......", "default": true } ] }
Stacktrace
W/MSALLogger: AuthorizationFragment:onCreate | [2022-11-11 13:11:47 - thread_name: main, correlation_id: UNSET - Android 31] No stored state. Unable to handle response W/AuthorizationFragment:onCreate: [2022-11-11 13:11:47 - thread_name: main, correlation_id: UNSET - Android 31] No stored state. Unable to handle response E/MSALLogger: AuthorizationFragment#finish | [2022-11-11 13:11:47 - thread_name: main, correlation_id: UNSET - Android 31] Logged as error to capture 'cause'; Exception occurred when removing ourselves from provided FragmentManager java.lang.IllegalStateException: FragmentManager is already executing transactions at androidx.fragment.app.FragmentManager.ensureExecReady(FragmentManager.java:1636) at androidx.fragment.app.FragmentManager.execSingleAction(FragmentManager.java:1666) at androidx.fragment.app.BackStackRecord.commitNow(BackStackRecord.java:317) at com.microsoft.identity.common.internal.providers.oauth2.AuthorizationFragment.finish(AuthorizationFragment.java:136) at com.microsoft.identity.common.internal.providers.oauth2.AuthorizationFragment.onCreate(AuthorizationFragment.java:94) at com.microsoft.identity.common.internal.providers.oauth2.WebViewAuthorizationFragment.onCreate(WebViewAuthorizationFragment.java:104) at androidx.fragment.app.Fragment.performCreate(Fragment.java:2981) at androidx.fragment.app.FragmentStateManager.create(FragmentStateManager.java:474) at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:257) at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1840) at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1758) at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1701) at androidx.fragment.app.FragmentManager$4.run(FragmentManager.java:488) at android.os.Handler.handleCallback(Handler.java:938) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loopOnce(Looper.java:226) at android.os.Looper.loop(Looper.java:313) at android.app.ActivityThread.main(ActivityThread.java:8663) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:567) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1135)
To Reproduce
-
Create the fragment where you would like to have the WebView. As example, in sample app. it can be “MultipleAccountModeFragment” from the sample app.
-
Set the WebView client for “authorization_user_agent” : “WEBVIEW”,
-
Add the “withFragment” to
val parameters: AcquireTokenParameters = AcquireTokenParameters.Builder() .withScopes(AzureUserAuthorizationApi.SCOPES) .startAuthorizationFromActivity(requireActivity())// we are inside fragment .withCallback(b2cAuthenticationCallback) *.withFragment(*this*)// this equals MultipleAccountModeFragment* .withPrompt(Prompt.LOGIN) .build()
-
call IMultipleAccountPublicClientApplication.acquireToken(parameters)
Expected behavior I would like to have the WebView is run inside the fragment/over MultipleAccountModeFragment. Also, I checked all the provided documentation, samples and I’ve not found anything how to use “withFragment” method correctly. I kindly ask to document it and it can save a lot of time for developers. Right know it doesn’t work.
Actual Behavior The error log message is observed, the spinner is running.
I found that it by some reasons “savedInstanceState” and “mInstanceState” is null and it closes itself onCreate.
AuthorizationFragment.java
if (savedInstanceState == null && mInstanceState == null) { Logger.warn(methodTag, "No stored state. Unable to handle response"); **finish();** return; }
Issue Analytics
- State:
- Created 10 months ago
- Comments:14
Top GitHub Comments
I found the workaround. Just create the same class in your project with the same package and Java runtime will use your class instead. Please take the fix here: https://github.com/AzureAD/microsoft-authentication-library-common-for-android/pull/1704
I still see the error about fragment transaction, but it works.
I was able to get this working in release. TLDR; it takes some work.
For my purposes, I wanted to replace both
AndroidAuthorizationStrategy.java
(this bug) andWebViewAuthorizationFragment.java
(I needed access to the webview) with my own implementations.You may want to get a coffee (or beverage of your choice) before attempting the following:
Removing the necessary files from the library
.gradle/caches/modules-2/files-2.1/com.microsoft.identity/common/9.0.0
)classes.jar
exists. I renamed its extension to a .zip and unzipped its contents..class
files for bothAndroidAuthorizationStrategy
andWebViewAuthorizationFragment
jar cvf classes.jar classes
jar cvf microsoft-common.aar common-9.0.0
Importing the AAR in your project successfully
I added
microsoft-common.aar
toapp/libs/
in my project (libs may be a new directory that you need to create).In the
dependencies
section of my appbuild.gradle
:Result
Now I can build a release build with both
com.microsoft.identity.common.internal.providers.oauth2.AndroidAuthorizationStrategy.java
andcom.microsoft.identity.common.internal.providers.oauth2.WebViewAuthorizationFragment.java
existing in my project. You can grab these classes from https://github.com/AzureAD/microsoft-authentication-library-common-for-android/tree/dev/common/src/main/java/com/microsoft/identity/common/internal/providers/oauth2For those who trust a random on GitHub providing them with a modified AAR, I have attached mine below. For those who don’t, just follow the Removing the necessary files from the library steps above.
microsoft-common.aar.zip