openid / AppAuth-Android

Android client SDK for communicating with OAuth 2.0 and OpenID Connect providers.
https://openid.github.io/AppAuth-Android
Apache License 2.0
2.82k stars 880 forks source link

Response state param did not match request state #852

Open kevinlee-app opened 2 years ago

kevinlee-app commented 2 years ago

Configuration

Description

Recently we tried to update the AppAuth-Android version used on our project from version 0.5.1.5 to 0.11.1. When successfully login from the browser and come back to the app, there is error data and we can't continue the process.

This is how we request:

AuthorizationServiceConfiguration configuration = new AuthorizationServiceConfiguration(Uri.parse(getAuthorizationRequestUrlWithParams(getBaseUrl(), getAuthorizationUrlParameters())), Uri.parse(getAccessTokenUrl()), null);

AuthorizationRequest.Builder authRequestBuilder = new AuthorizationRequest.Builder(
                    configuration,
                    mClientId,
                    "code token id_token",
                    Uri.parse(getCallbackURI()))
                    .setScope(getHybridScope());

Intent completionIntent = new Intent(context, tokenActivity);
Intent cancelIntent = getCancelIntent(context, cancelActivity);
CustomTabColorSchemeParams colorSchemeParams = new CustomTabColorSchemeParams.Builder()
                    .setToolbarColor(ContextCompat.getColor(context,R.color.grey120))
                    .setSecondaryToolbarColor(ContextCompat.getColor(context,R.color.black))
                    .build();

int flags = 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
    flags |= PendingIntent.FLAG_MUTABLE;
}

mAuthService.performAuthorizationRequest(
                    authRequestBuilder.build(),
                    PendingIntent.getActivity(context, 0, completionIntent, flags),
                    PendingIntent.getActivity(context, 0, cancelIntent, flags),
                    mAuthService.createCustomTabsIntentBuilder()
                            .setDefaultColorSchemeParams(colorSchemeParams)
                            .build());

On authorization completed, the responseData has error data with description Response state param did not match request state.

After some debugging, we found out that on AuthorizationResponse.java there is a builder function that failed to get the query parameters from Uri which result in null value although the Uri string already contains all the data.

We also tried to setResponseMode to "form_post" on authRequestBuilder when requesting but it looks like it's still not supported.

Does anyone happen to solved this before? Thanks in advance.

kostadin-damyanov-prime commented 2 years ago

I have the same issue. It seems to be happening on anndroid emulator consistently. @kevinlee-app did you find a solution?

Cantinaband commented 1 year ago

Facing the same error. Sometimes on real devices but every-time on android emulator. Any updates / suggestions here?

HesamKamalan commented 10 months ago

I have a similar code as you put in the description. I receive a same error message, The Response state param did not match the request state, When I test my app on devices running with Android 9.0 and below. However, log in functionality goes well on Android 10 and above. I don't know if there is any restriction by the library!

Radiokot commented 10 months ago

I think there is a bug in the library. You get this error when using the Implicit flow (response type token), where auth result is passed to the client not through query params (?) but through reference/fragment (#): my-app://oauth2redirect#state=Rve0AbxNWLEx6StF99Fg_Q&session_state=e40fe780-3942-4501-a254-... But the library always expects the response to be in query params and so fails to parse it: https://github.com/openid/AppAuth-Android/blob/c6137b7db306d9c097c0d5763f3fb944cd0122d2/library/java/net/openid/appauth/AuthorizationResponse.java#L225-L227

Radiokot commented 10 months ago

I suggest using explicit flow (response type code) until it is fixed 🤷‍♂️

wyllyamjesus-hotmart commented 10 months ago

@Radiokot Could you make an example of what this code would look like? I'm going through the same problem

Radiokot commented 10 months ago

@wyllyamjesus-hotmart

  1. You set the response type of your authorization request to ResponseTypeValues.CODE
  2. Once you've received AuthorizationResponse in your activity, get the access token by authService.performTokenRequest(authResponse.createTokenExchangeRequest())

This is the flow described in the library readme: https://github.com/openid/AppAuth-Android/#implementing-the-authorization-code-flow

wyllyamjesus-hotmart commented 10 months ago

@Radiokot

I have already implemented this flow, but it still has problems, from the logs I received in Firebase's crashlytics, the problem is occurring within the AuthorizationManagementActivity class, in the extractResponseData function (line 342). The flow enters the else and after that the problem occurs in the if as it does not include validation.

Radiokot commented 10 months ago

@wyllyamjesus-hotmart then I think this is not the implicit flow issue, can't help you with that.

HesamKamalan commented 10 months ago

I have a similar code as you put in the description. I receive a same error message, The Response state param did not match the request state, When I test my app on devices running with Android 9.0 and below. However, log in functionality goes well on Android 10 and above. I don't know if there is any restriction by the library!

I found something new. I could resolve my issue on a device with Android 9.0. It is something related to the Browser being used for authentication. As I am testing on Browserstack, whenever I launch a new device I get a fresh device. In this case, I am testing on Samsung S10 (Android 9). I get Response state param did not match request state error message as soon as I tap my Login button (Browser opens and closes instantly). Then I go to device settings/apps/Chrome and set it as my default browser. Then I launch my app and tap on the Login button. I can see the Login web page and complete the authentication.

So, I thought the issue was happening because I have AnyBrowserMatcher.INSTANCE in my AppAuthConfiguration. Then I changed it using the way mentioned here. I allow only CHROME_CUSTOM_TAB and SAMSUNG_CUSTOM_TAB. I launch a new device and install the app on a new device (on Browserstack). I launch the app and tap on the Login button. I still get the error message. I set Chrome as the default browser, launch the app and can see the login on the webpage. So, have no idea what these settings do. But at least we know the error is related to the picked browser.

davidkarlsson commented 9 months ago

As @Radiokot said the reason this happens seems to be because the pararmeters are appended to the redirect url in a URI fragment instead of as query parameters if you set the response type to id_token instead of code which AuthorizationResponse.Builder::fromUri can't parse by using uri.getQueryParameter.

The reason why this differs between the implicit grant and the authorization code grant is explained in detail here: https://community.auth0.com/t/the-redirect-response-does-not-send-the-hash-fragment-tokens-to-the-server-side/6180/2

Radiokot commented 9 months ago

I've also found that missing support for implicit grant flow is intentional. This flow is considered deprecated and unsafe (for good reasons), so the library maintainers do not want to implement it. However, this is confusing because there is the ResponseTypeValues.TOKEN constant available to use and not marked as deprecated or experimental. https://github.com/openid/AppAuth-Android/issues/221#issuecomment-298422560

svenjacobs commented 9 months ago

Just struggled with the same problem. It would be nice if ResponseTypeValues.TOKEN could be marked as deprecated.

adnan-wb commented 4 months ago

Facing the same issue, even I tried multiple packages but I couldn't find any response while my SSO server was working well. I am still facing the error " Error PlatformException(authorize_failed, Failed to authorize: [error: null, description: Response state param did not match request state], null, null)"