aws-amplify / amplify-android

The fastest and easiest way to use AWS from your Android app.
https://docs.amplify.aws/lib/q/platform/android/
Apache License 2.0
243 stars 115 forks source link

UserCancelledException after first Google Social Login / Logout #2744

Closed iolandarosavoid closed 5 months ago

iolandarosavoid commented 5 months ago

Before opening, please confirm:

Language and Async Model

Kotlin - Coroutines

Amplify Categories

Authentication

Gradle script dependencies

```groovy // Put output below this line implementation "com.amplifyframework:aws-api:2.14.12" implementation "com.amplifyframework:core-kotlin:2.14.12" implementation "com.amplifyframework:aws-auth-cognito:2.14.12" ```

Environment information

``` # Put output below this line Welcome to Gradle 8.2! Here are the highlights of this release: - Kotlin DSL: new reference documentation, assignment syntax by default - Kotlin DSL is now the default with Gradle init - Improved suggestions to resolve errors in console output For more details see https://docs.gradle.org/8.2/release-notes.html ------------------------------------------------------------ Gradle 8.2 ------------------------------------------------------------ Build time: 2023-06-30 18:02:30 UTC Revision: 5f4a070a62a31a17438ac998c2b849f4f6892877 Kotlin: 1.8.20 Groovy: 3.0.17 Ant: Apache Ant(TM) version 1.10.13 compiled on January 4 2023 JVM: 17.0.7 (JetBrains s.r.o. 17.0.7+0-17.0.7b1000.6-10550314) OS: Mac OS X 14.3.1 aarch64 ```

Please include any relevant guides or documentation you're referencing

https://docs.amplify.aws/android/build-a-backend/auth/sign-in-with-web-ui/

Describe the bug

Reproduction steps (if applicable)

  1. Look for Spartan Forge app in Play Store - https://play.google.com/store/search?q=spartan+forge&c=apps&hl=en&gl=US
  2. Install the app on your phone.
  3. Use the Google button to sign in / signup to the app.
  4. After entering your credentials in the web view, observe that the app redirects you to the subscription screen. (If the app redirects you to the map, you can skip steps 5 to 7.)
  5. On the subscription screen, check to confirm the option related to Terms & Conditions.
  6. Click on the link that says "Get limited access for free."
  7. Scroll down and click "Continue."
  8. Observe that you are redirected to the map.
  9. Open the drawer menu and verify that you are using version 1.13.3 of the app.
  10. Scroll through the drawer menu options to the bottom and select "Log out."
  11. Confirm the logout and observe that after the splash screen, you are redirected to the login screen.
  12. Click on Google to log in and observe the exception occurring.
  13. If you continue trying, you will notice that the exception consistently occurs.
  14. Go to your phone's "Settings" --> "Apps" --> and clear data from the default browser app.
  15. Return to the app's login page, click on login, and observe that you are able to log in successfully again.
  16. Repeat steps 10, 11, 12, and 13, and observe the exception occurring again.

Code Snippet

// Put your code below this line.

Log output

``` // Put your logs below this line UserCancelledException{message=The user cancelled the sign-in attempt, so it did not complete., cause=null, recoverySuggestion=To recover: catch this error, and show the sign-in screen again.} at com.amplifyframework.auth.cognito.RealAWSCognitoAuthPlugin$handleWebUISignInResponse$1.invoke(RealAWSCognitoAuthPlugin.kt:1076) at com.amplifyframework.auth.cognito.RealAWSCognitoAuthPlugin$handleWebUISignInResponse$1.invoke(RealAWSCognitoAuthPlugin.kt:1026) at com.amplifyframework.statemachine.StateMachine$getCurrentState$1.invokeSuspend(StateMachine.kt:121) at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:104) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:487) at java.util.concurrent.FutureTask.run(FutureTask.java:264) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:307) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:644) at java.lang.Thread.run(Thread.java:1012) ```

amplifyconfiguration.json

{
    "UserAgent": "aws-amplify-cli/2.0",
    "Version": "1.0",
    "api": {
        "plugins": {
            "awsAPIPlugin": {
                "webhookEndpoint": {
                    "endpointType": "REST",
                    "endpoint": "xxxx",
                    "region": "us-east-1",
                    "authorizationType": "AWS_IAM"
                },
                "outfitterEndpoint": {
                    "endpointType": "REST",
                    "endpoint": "xxxx",
                    "region": "us-east-1",
                    "authorizationType": "AWS_IAM"
                },
                "outfitterGQL": {
                    "endpointType": "GraphQL",
                    "endpoint": "xxxx",
                    "region": "us-east-1",
                    "authorizationType": "AMAZON_COGNITO_USER_POOLS"
                }
            }
        }
    },
    "auth": {
        "plugins": {
            "awsCognitoAuthPlugin": {
                "UserAgent": "aws-amplify-cli/0.1.0",
                "Version": "0.1.0",
                "IdentityManager": {
                    "Default": {}
                },
                "CredentialsProvider": {
                    "CognitoIdentity": {
                        "Default": {
                            "PoolId": "xxxx",
                            "Region": "us-east-1"
                        }
                    }
                },
                "CognitoUserPool": {
                    "Default": {
                        "PoolId": "xxxx",
                        "AppClientId": "xxxx",
                        "Region": "us-east-1"
                    }
                },
                "GoogleSignIn": {
                    "Permissions": "email,profile,openid",
                    "ClientId-WebApp": "xxxx"
                },
                "FacebookSignIn": {
                    "AppId": "xxxx",
                    "Permissions": "public_profile"
                },
                "Auth": {
                    "Default": {
                        "OAuth": {
                            "WebDomain": "xxxx",
                            "AppClientId": "xxxx",
                            "SignInRedirectURI": "xxxx",
                            "SignOutRedirectURI": "xxxx",
                            "Scopes": [
                                "phone",
                                "email",
                                "openid",
                                "profile",
                                "aws.cognito.signin.user.admin"
                            ]
                        },
                        "authenticationFlowType": "USER_SRP_AUTH",
                        "loginMechanisms": [
                            "EMAIL",
                            "FACEBOOK",
                            "GOOGLE",
                            "APPLE"
                        ],
                        "signupAttributes": [
                            "EMAIL"
                        ],
                        "passwordProtectionSettings": {
                            "passwordPolicyMinLength": "-",
                            "passwordPolicyCharacters": []
                        },
                        "mfaConfiguration": "OFF",
                        "mfaTypes": [
                            "SMS"
                        ]
                    }
                },
                "S3TransferUtility": {
                    "Default": {
                        "Bucket": "xxxx",
                        "Region": "us-east-1"
                    }
                },
                "DynamoDBObjectMapper": {
                    "Default": {
                        "Region": "us-east-1"
                    }
                },
                "AppSync": {
                    "Default": {
                        "ApiUrl": "xxxx",
                        "Region": "us-east-1",
                        "AuthMode": "AMAZON_COGNITO_USER_POOLS",
                        "ClientDatabasePrefix": "xxxx"
                    },
                    "outfitterGQL_AWS_IAM": {
                        "ApiUrl": "xxxx",
                        "Region": "us-east-1",
                        "AuthMode": "AWS_IAM",
                        "ClientDatabasePrefix": "xxxx"
                    }
                }
            }
        }
    },
    "storage": {
        "plugins": {
            "awsS3StoragePlugin": {
                "bucket": "xxxx",
                "region": "us-east-1",
                "defaultAccessLevel": "guest"
            },
            "awsDynamoDbStoragePlugin": {
                "partitionKeyName": "xxxx",
                "sortKeyName": "xxxx",
                "sortKeyType": "x",
                "region": "us-east-1",
                "arn": "xxxx",
                "streamArn": "xxxx",
                "partitionKeyType": "X",
                "name": "xxxx"
            }
        }
    }
}

GraphQL Schema

```graphql // Put your schema below this line ```

Additional information and screenshots

AndroidManifest info

<application (...)>
(...)
       <activity
            android:name="com.amplifyframework.auth.cognito.activities.HostedUIRedirectActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />

                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />

                <data android:scheme="ai.spartanforge.outfitter" />
            </intent-filter>
        </activity>
(...)
</application>
tylerjroach commented 5 months ago

@iolandarosavoid I will try and replicate the issue.

It is expected that you will not be signed out from Google on a hosted ui social sign in. Since the authentication cookie is in the browser (ex: chrome) and for a non-cognito site, we cannot sign the Google user out.

It is not expected that a subsequent sign in attempt completely fails though. I'll try to replicate with my own google hosted ui sign in app and send an update.

tylerjroach commented 5 months ago

I tested with my sample app with Google Social sign ins and I am able to sign in and out continuously without error.

Just to confirm, both your sign in and sign out redirect uris configured on Cognito side start with ai.spartanforge.outfitter.

Would also be good to double check Google sign in settings for Authorized JavaScript origins includes your Amplify hostedui endpoint, and that Authroized redirect URIs includes /oauth2/idpresponse

iolandarosavoid commented 5 months ago

Yes, I confirm that the redirect URI starts with ai.spartanforge.outfitter. I will double-check the information in Google settings.

Additionally, I was able to replicate the current bug with another Samsung phone running Android 14, using the default browser app as Chrome (Galaxy A53 5G). However, when I used another phone (TCL 30) with Android 12, the bug did not occur, and everything proceeded as expected.

Furthermore, I discovered that if I have Chrome browser and more than one Google account associated with the device, the bug never occurs, even when using the Samsung phones that previously exhibited the bug. Hence, this seems to be a very specific situation that I was able to reproduce only on Samsung devices until now running Android 14 and with only one Google account associated with the device.

I'm not sure if you attempted to reproduce the bug under these conditions.

iolandarosavoid commented 5 months ago

Also very important to point out is that I installed a previous version of the app that still uses authentication version 1 (1.37.5) and this bug does not happen on the same devices and with the conditions I explained before. This only started to happen after update to version 2.

tylerjroach commented 5 months ago

@iolandarosavoid I'll try and replicate this on Android 14. I am aware of another issue we observed with Hosted UI in one of our other libraries: https://github.com/aws-amplify/aws-sdk-android/issues/3530.

It would be helpful to understand what the launchMode is for the Activity that sign in and sign out are occurring on.

My tests involved a single Google account signed into the browser on a phone, but I believe I was testing with Android 13 at the time.


One thing I want to mention is that there is a difference in sign out behavior for Amplify v1 and Amplify v2. Amplify v1 does not rely on a successful sign out from the browser to complete the sign out process and locally clear credentials on the device.

To ensure we were more thorough in ensuring proper sign outs, Amplify v2 requires that the browser acknowledges it has signed out, before continuing to sign out locally (wiping stored credentials).

Its likely that in your v1 testing, a similar issue is being encountered, but silently continuing.

iolandarosavoid commented 5 months ago

@tylerjroach thank you so much for pointing out that issue.

The activity that launches the web sign-in was indeed set in manifest with the launchMode="singleInstance". I change it to launchMode="singleTop" and it solve the issue. It's now working fine.

Thanks for your help.

tylerjroach commented 5 months ago

That's great to hear! Thank you for your feedback. I wasn't sure if this scenario was also going to be relevant to your case but happy to hear that it resolved the issue for you. If you determine that "singleInstance" is required in your application, be sure to see the wrapper workaround that I posted: https://github.com/aws-amplify/aws-sdk-android/issues/3530#issuecomment-1944149153

github-actions[bot] commented 5 months ago

This issue is now closed. Comments on closed issues are hard for our team to see. If you need more assistance, please open a new issue that references this one.