Appauth-android: Redirect is not fetched by Activity per intent - for all subsequent starts of an application. The first time it works.

Created on 7 Apr 2021  Â·  22Comments  Â·  Source: openid/AppAuth-Android

Configuration

  • Version: 0.8.1
  • Integration: Java on Android
  • Identity provider: our own

Description

Following the documentation I set up a small application doing the AuthGrant with our own IDP.

URI Receiver Activity configuration:

        <activity
            android:name="net.openid.appauth.RedirectUriReceiverActivity"
            tools:node="replace">
            <tools:validation testUrl="https://_host.domain.com_/oauth" />
            <intent-filter android:autoVerify="true">
                <action android:name="android.intent.action.VIEW"/>
                <category android:name="android.intent.category.DEFAULT"/>
                <category android:name="android.intent.category.BROWSABLE"/>
                <data android:scheme="https"
                android:host="_host.domain.com_"
                    android:path="/oauth"/>
            </intent-filter>
        </activity>

The java implementation is taken straight forward from the documentaion:

    protected void doit() {

        AuthorizationServiceConfiguration.fetchFromUrl(
                Uri.parse("https://_idp.somewhere.com_/.well-known/openid-configuration"),
                new AuthorizationServiceConfiguration.RetrieveConfigurationCallback() {
                    public void onFetchConfigurationCompleted(
                            @Nullable AuthorizationServiceConfiguration serviceConfiguration,
                            @Nullable AuthorizationException ex) {
                        if (ex != null) {
                            Log.e(TAG, "failed to fetch configuration",ex);
                            return;
                        }
                        else {
                            Log.i(TAG,"Obtaining AuthCode...");
                            obtainAuthCode(serviceConfiguration);
                        }
                        // use serviceConfiguration as needed
                    }
                });
    }

    protected void obtainAuthCode(AuthorizationServiceConfiguration serviceConfiguration) {
        AuthorizationRequest.Builder authRequestBuilder =
                new AuthorizationRequest.Builder(
                        serviceConfiguration, // the authorization service configuration
                        MY_CLIENT_ID, // the client ID, typically pre-registered and static
                        ResponseTypeValues.CODE, // the response_type value: we want a code
                        Uri.parse(MY_REDIRECT_URI)); // the redirect URI to which the auth response is sent

        AuthorizationRequest authRequest = authRequestBuilder
                .setScope("openid email profile")
                .setLoginHint("Password hint")
                .build();
        Log.i(TAG,"Starting AuthRequest...");
        doAuthorization(authRequest);
    }

    private void doAuthorization(AuthorizationRequest authRequest) {
        authService = new AuthorizationService(this);
        Intent authIntent = authService.getAuthorizationRequestIntent(authRequest);
        startActivityForResult(authIntent, RC_AUTH);
    }

    @SuppressLint("MissingSuperCall")
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == RC_AUTH) {

            AuthorizationResponse resp = AuthorizationResponse.fromIntent(data);
            AuthorizationException ex = AuthorizationException.fromIntent(data);

            if (resp != null) {
                Log.i(TAG,"Got AuthCode: "+resp.authorizationCode);
                // authorization completed
                Log.i(TAG,"Obtaining AccessToken...");
                obtainToken(resp);
            } else {
                // authorization failed, check ex for more details
            }
        } else {
            // ...
        }
    }

First time - after booting the emulator completly everything works fine. If I stop all tasks on the emulator and restart the application the app link is not consumed by the Activity but Chrome is presenting the AuthCode Redirect inside the browser.
The Digital Asset Links is available per https and all tests state everything is ok. It's also working the first time.

I only struggle with starting my app a 2nd or 3rd (...) time. The Redirect ist not fetched by my app. What might the issue here?

question waiting-for-response

All 22 comments

Have you verified the app link works properly and opens your app?
adb shell am start -a android.intent.action.VIEW -c android.intent.category.BROWSABLE -d "https://_host.domain.com_/oauth"

If that works, please make sure the link policy is always via adb shell dumpsys package d
Can also be checked/changed in Settings / Apps & Notifications / Defaults apps / Opening Links

@kawomm Try to add like this :

<data
  android:host="auth"
  android:scheme="msal{clientid}" />

android:path="msalclientId">

@Saitarak436 Using a custom scheme does make the integration a lot easier, but the OP did mention using https and having configured Digital Asset Links. Thank you for your suggestion though.

@Saitarak436 Using a custom scheme does make the integration a lot easier, but the OP did mention using https and having configured Digital Asset Links. Thank you for your suggestion though.

Hi,

@Saitarak436 - thanks for your advice. As written by @agologan I have to use the URL-based scheme with digital asset links. As I wrote, the digital asset link seem to work. First start of the application (including appauth authorization process) works perfectly. My problem is the 2nd start - maybe I do not understand AuthSTate correctly, which I'm currently not using at all and I'm expecting the application to walk through the same autorization process - what the application does not. It stops showing the CustomChromeTab with the REDIRECT URL not beeing redirected. It also could be that the ChromeCustomTab is just showing the "last" call (from the first invocation) and I do understand something completely wrong with the ChromeCustomTab and/or activities.

Have you verified the app link works properly and opens your app?
adb shell am start -a android.intent.action.VIEW -c android.intent.category.BROWSABLE -d "https://_host.domain.com_/oauth"

If that works, please make sure the link policy is always via adb shell dumpsys package d
Can also be checked/changed in Settings / Apps & Notifications / Defaults apps / Opening Links

calling the dumpsys command results in

  Package: package.login
  Domains: _host.domain.com_
  Status:  always : 200000000 

I'm stumped - per the information provided everything should be working fine.
Probably missing something, recommend you switch over to a custom scheme and verify the workflow works so we can rule that out before figuring why App Links are giving you trouble.

Thanks for your time! I still have the same issue, but I'm sure in the meanwhile it's not an appauth issue. I found in the meanwhile a video on youtube https://www.youtube.com/watch?v=Y-4uLpUv1lA showing a similar problem (second 11). the second Login fails. I will do some more investigations.

If the issue you're describing matches the video then you've probably running into the following problem.
According to the current chrome docs, chrome will not launch an external application without a user interaction. (Ref: https://developer.chrome.com/docs/multidevice/android/intents/)
Further info: https://bugs.chromium.org/p/chromium/issues/detail?id=738724

The issue can be alleviated by:
• ensuring the user is logged out before logging back in
• asking him to always relogin by adding prompt:login to the auth request.
• asking the identity provider to have an account confirmation step if an user is already logged in when opening the chrome custom tab

If the issue you're describing matches the video then you've probably running into the following problem.
According to the current chrome docs, chrome will not launch an external application without a user interaction. (Ref: https://developer.chrome.com/docs/multidevice/android/intents/)
Further info: https://bugs.chromium.org/p/chromium/issues/detail?id=738724

The issue can be alleviated by:
• ensuring the user is logged out before logging back in
• asking him to always relogin by adding prompt:login to the auth request.
• asking the identity provider to have an account confirmation step if an user is already logged in when opening the chrome custom tab

I read already about this. Don't get me wrong, this would lead to a non-functioning of the SSO login idea based on a weblogin session cookie. Normally I only do one single interaction as a user. After that the session cookie is enough to present to a weblogin in a subsequent case. No interaction at all. Second, it seems that even no AuthCodeFlow is executed in my case. I checked the tokenissuer logs. Third, I can bring it back to work again by just starting Chrome and close the task completly. Than it works for another time. It looks for me like a case where crhomecustomtabs are not willing to reexecute the same call completly, but just delivering the latest respons (not interceptable by the app)

If the issue you're describing matches the video then you've probably running into the following problem.
According to the current chrome docs, chrome will not launch an external application without a user interaction. (Ref: https://developer.chrome.com/docs/multidevice/android/intents/)
Further info: https://bugs.chromium.org/p/chromium/issues/detail?id=738724
The issue can be alleviated by:
• ensuring the user is logged out before logging back in
• asking him to always relogin by adding prompt:login to the auth request.
• asking the identity provider to have an account confirmation step if an user is already logged in when opening the chrome custom tab

I read already about this. Don't get me wrong, this would lead to a non-functioning of the SSO login idea based on a weblogin session cookie. Normally I only do one single interaction as a user. After that the session cookie is enough to present to a weblogin in a subsequent case. No interaction at all. Second, it seems that even no AuthCodeFlow is executed in my case. I checked the tokenissuer logs. Third, I can bring it back to work again by just starting Chrome and close the task completly. Than it works for another time. It looks for me like a case where crhomecustomtabs are not willing to reexecute the same call completly, but just delivering the latest respons (not interceptable by the app)

although.... Since I activated the "remember me" = session cookie it shows constantly the behaviour of not redirecting. But honestly, this is not what i expect from a SSO solution. Now I'm the one beeing completly stumped.

Ok, it's the User Interaction. Putting an Webpage in between the process, makes it work completely. I tried to simulate the click in Javascript -> doesn't work. Clicking manually it works.

But help me: Is this what the community expects from a SSO experience? Am I the only one being a bit - who should I say - astonished? Is this telling my implicitly to not use COOKIE based SSO any more and distribute REFRESH TOKENS throughout the devices to use them as Re-Login mechanism? Is this more secure? A twelve month valid token out there? On a public device?

```

 

OAuth2 Login Experience  

   



```

I understand your frustration but your replies are not very constructive.
It would be helpful if you described the experience you're trying to achieve.
You are not the first to run into these issues and a search through existing issues will highlight that.
But your use-case and expectations may be different to other developers.
Also please keep in mind we can only offer advice in the scope of the existing system limitations.

In the case of a mobile application we don't expect users to need to interact with a webView outside of their initial login.
Using access tokens and refresh tokens correctly may be more secure, and although refresh tokens are longer lived it doesn't mean they need to have a very long lifespan.
A good implementation would make use of the sliding window aspect of the Oauth issuing shorter lived refresh tokens, and expanding the session only if there is user activity.
You can expand the session by issuing a new refresh token with the access token during a refresh.

Have you verified the app link works properly and opens your app?
adb shell am start -a android.intent.action.VIEW -c android.intent.category.BROWSABLE -d "https://_host.domain.com_/oauth"

If that works, please make sure the link policy is always via adb shell dumpsys package d
Can also be checked/changed in Settings / Apps & Notifications / Defaults apps / Opening Links

I was getting a similar problem on Android 11 where returning URL not taking user back to the app. I am not sure if it is something OS related issu! But after running this command line it asks me to choose between my app and chrome browser. I chose app and marked as Always. After that I did not find the problem. However, this seems to be an issue when real users try to do SSO and stuck in browser post login on redirect URL.!! Don't know how could it be resolved in the code to know that our return URL is for the app only and not for chrome browser.

@sundeepkmallick the disambiguation dialog (the dialog to choose which app to use) is only shown if App Links are not configured/loaded. Ensure you have published the digital assets link (assetslinks.json) and that your intent filter is set to android:autoVerify="true". If both of these are configured, verify your config via the Google portal and verify your device actually loaded the values via dumpsys as explained above.

I have same issue. Any solution?

@huynguyennovem do you mind describing your actual problem, and what you tried?

There are about 5 replies touching on the original OPs problem.
The OP himself has described various approaches, although unhappy with the outcome.

Saying you have the same issue and asking for a solution without providing further information is not helpful in this case.

@huynguyennovem do you mind describing your actual problem, and what you tried?

There are about 5 replies touching on the original OPs problem.
The OP himself has described various approaches, although unhappy with the outcome.

Saying you have the same issue and asking for a solution without providing further information is not helpful in this case.

Thank for quickly responding to me. In my case:

<intent-filter android:autoVerify="true">
    <action android:name="android.intent.action.VIEW"/>
    <category android:name="android.intent.category.DEFAULT"/>
    <category android:name="android.intent.category.BROWSABLE"/>
    <data android:scheme="https" android:host="console.auth.app" android:path="/oidccallback"/>
</intent-filter>

The first time, RedirectUriReceiverActivity can be invoked. But from the second time, it does not.
And when I cleared the cache of browser (Chrome for eg), it worked again

Per my current understanding: https://github.com/openid/AppAuth-Android/issues/679#issuecomment-824091995 chrome will launch an external app only on user interaction.
In an SSO scenario my recommendation it to ask the user the select the account he's currently logging in even if there is an active session.
Having an intermediary page can also resolve the issue of the user wanting to switch accounts if he's already logged into something else.

Hi @agologan , what about logout situation https://github.com/openid/AppAuth-Android/issues/701 ? Is it related here? There also redirection happening and user is redirected to the universal link and stuck. Do we need to add some HTML/JavaScript code on universal return uri page so that user could press the button manually to come back to the app? And if yes, do you have any reference? If no, what is missing from my side?

Per my current understanding: #679 (comment) chrome will launch an external app only on user interaction.
In an SSO scenario my recommendation it to ask the user the select the account he's currently logging in even if there is an active session.
Having an intermediary page can also resolve the issue of the user wanting to switch accounts if he's already logged into something else.

It may be a solution for this. Currently, I found that we can clear the cookie when it is stucked from second time, then try again to see it work as well. Still need to investigate more to handle this issue. Anyway, thank you for supporting!

@huynguyennovem there are other options like asking the user to login every time via prompt:login but it really depends on your product's expectations.

@sundeepkmallick been meaning to reply to your issue. Yes I do believe it stems from the same limitation.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Jawnnypoo picture Jawnnypoo  Â·  3Comments

zamzterz picture zamzterz  Â·  6Comments

Smedzlatko picture Smedzlatko  Â·  7Comments

tomjackman picture tomjackman  Â·  7Comments

hallerio picture hallerio  Â·  7Comments