amplify-android
amplify-android copied to clipboard
UserCancelledException
Before opening, please confirm:
- [X] I have searched for duplicate or closed issues and discussions.
Language and Async Model
Kotlin, Kotlin - Coroutines
Amplify Categories
Authentication
Gradle script dependencies
// Put output below this line
implementation 'com.amplifyframework:aws-auth-cognito:2.12.0'
implementation 'com.amplifyframework:core:2.12.0'
implementation 'com.amazonaws:aws-android-sdk-auth-userpools:2.73.0'
implementation 'com.amazonaws:aws-android-sdk-auth-ui:2.73.0'
Environment information
# Put output below this line
------------------------------------------------------------
Gradle 8.3
------------------------------------------------------------
Build time: 2023-08-17 07:06:47 UTC
Kotlin: 1.9.0
Groovy: 3.0.17
Please include any relevant guides or documentation you're referencing
https://docs.amplify.aws/android/build-a-backend/auth/sign-in-with-web-ui/#launch-web-ui-sign-in
Describe the bug
When using Amplify.Auth.signInWithWebUI(activity)
after successfully logging out, I occasionally get the UserCancelledException
with no interaction with webview window.
Reproduction steps (if applicable)
- Call the sign out method then, within the sign out callback, call the
signInWithWebUI
method. - See the
UserCancelledException
after going through this process a few times.
Note: This is not consistent as to when the exception is returned. Sometimes it takes a couple times, sometimes many more.
Code Snippet
// Put your code below this line.
fun signInWithWebUI(
activity: Activity,
callback: (String?, AmplifyException?) -> Unit,
) {
signOut { success, error ->
Amplify.Auth.signInWithWebUI(activity,
{
fetchCurrentAuthSession(callback)
},
{
Log.e("", "Signin failed", it)
}
)
}
}
fun signOut(callback: (success: Boolean, error: Exception?) -> Unit) {
Amplify.Auth.signOut { signOutResult ->
when (signOutResult) {
is AWSCognitoAuthSignOutResult.CompleteSignOut -> {
Log.d("QuickstartApp", "cognito signout success")
callback.invoke(true, null)
}
is AWSCognitoAuthSignOutResult.PartialSignOut -> {
signOutResult.hostedUIError?.let {
callback.invoke(false, it.exception)
Log.d("QuickstartApp", "hostedUI error: ${it.exception.localizedMessage}")
// Optional: Re-launch it.url in a Custom tab to clear Cognito web session.
}
signOutResult.globalSignOutError?.let {
Log.e("QuickstartApp", "GlobalSignOut Error", it.exception)
callback.invoke(false, it.exception)
// Optional: Use escape hatch to retry revocation of it.accessToken.
}
signOutResult.revokeTokenError?.let {
Log.e("QuickstartApp", "RevokeToken Error", it.exception)
callback.invoke(false, it.exception)
// Optional: Use escape hatch to retry revocation of it.refreshToken.
}
}
is AWSCognitoAuthSignOutResult.FailedSignOut -> {
Log.d("QuickstartApp", "FailedSignOut: ${signOutResult.exception.localizedMessage}")
callback.invoke(false, signOutResult.exception)
}
}
}
}
fun fetchCurrentAuthSession(callback: (String?, AmplifyException?) -> Unit) {
Amplify.Auth.fetchAuthSession(
{
val session = it as AWSCognitoAuthSession
val token = session.userPoolTokensResult.value?.idToken
Log.d("QuickstartApp", "fetchCurrentAuthSession: $token")
callback(token, null)
},
{
Log.e("QuickstartApp", "Failed to fetch auth session: ${it.localizedMessage}")
callback(null, it)
}
)
}
Log output
// Put your logs below this line
Signin failed 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:928) at com.amplifyframework.auth.cognito.RealAWSCognitoAuthPlugin$handleWebUISignInResponse$1.invoke(RealAWSCognitoAuthPlugin.kt:878) 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:108) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:463) 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:1137) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:637) at java.lang.Thread.run(Thread.java:1012)
amplifyconfiguration.json
val categoryConfig = JSONObject( "{\n" + " "auth": {\n" + " "plugins": {\n" + " "awsCognitoAuthPlugin": {\n" + " "IdentityManager": {\n" + " "Default": {}\n" + " },\n" + " "CognitoUserPool": {\n" + " "Default": {\n" + " "PoolId": "${BuildConfig.AMPLIFY_POOL_ID}",\n" + " "AppClientId": "${BuildConfig.AMPLIFY_CLIENT_ID}",\n" + " "Region": "us-east-2"\n" + " }\n" + " },\n" + " "Auth": {\n" + " "Default": {\n" + " "authenticationFlowType": "USER_SRP_AUTH",\n" + " "OAuth": {\n" + " "WebDomain": "${BuildConfig.AMPLIFY_WEB_DOMAIN}",\n" + " "AppClientId": "${BuildConfig.AMPLIFY_CLIENT_ID}",\n" + " "SignInRedirectURI": "xxxxxx://signin",\n" + " "SignOutRedirectURI": "xxxxxx://signout",\n" + " "Scopes": [\n" + " "email",\n" + " "openid",\n" + " "profile",\n" + " "aws.cognito.signin.user.admin"\n" + " ]\n" + " }\n" + " }\n" + " }\n" + " }\n" + " }\n" + " }\n" + "}" )
GraphQL Schema
// Put your schema below this line
Additional information and screenshots
No response
I've noticed that you are mixing Amplify v2 and our AWS Mobile SDKs. These libs are not compatible with each other and have a good chance of being the issue you are running into.
I've removed the dependencies that weren't used and only kept the two amplify dependencies. I'm still seeing the issue.
implementation 'com.amplifyframework:core:2.12.0' implementation 'com.amplifyframework:aws-auth-cognito:2.12.0'
@tfreeman82 There is only 1 block in the library that triggers UserCancelledException: https://github.com/aws-amplify/amplify-android/blob/f3f8caf5ba3bbd26514ce9678cb6e161f0161c04/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/RealAWSCognitoAuthPlugin.kt#L1058
This happens when the intent.data
is null, which means we did not receive any intent data back from the web browswer..
I'm noticing that in your case, and additionally, the previous similar issue with UserCancelledException, both code examples are showing signInWithWebUI
immediately being called after signOut
. This makes me speculate that their could be a race condition here where if the browser is immediately reopened (It opens momentarily, even if you don't see it, to sign out the Cognito hosted ui session), it may send back the previous intent (from the sign out).
While I don't necessarily encourage the use of a sleep/wait block, if you are able to replicate this on a test device, could you wait for a short period of time (ex: 500ms) before triggering signInWithWebUI
after signOut has returned? This would help pin down where the issue lies.
I'm curious of your use case to call signOut and then signIn immediately after. Is the signOut call always necessary beforehand? It would be best to check if you are already signed in first, and only sign out in that case.
The decision to call signOut before signInWithWebUI was made because we only have a few clients that use SSO and didn't want to affect every user with the signOut process because of the way it opens the browser to handle the sign out process.
Instead, we decided to add it to the tap of the SSO sign in button so that only the users who use it see the window open and close.
With that being said, I added a 500ms delay between the signOut success and the signInWithWebUI call and no longer see the error.
Thanks for your response. I'll further investigate if there are improvements that can be made on our end, and where this race condition lies.