Closed Sserra90 closed 3 years ago
Hi @Sserra90, I tried to clean up your issue a bit ... but I'm not sure I get it still. Can you help out a bit?
amplifyProxy
?AWSMobileClient
? If so, can you include line links, in addition to the inline Java blocks?Hi @jamesonwilliams thanks for the reply. Let me try to clarify this a little.
amplifyProxy
just proxy calls to real Amplify instance, it's here just to ease unit testing, so we can remove it from the example.After some more research i can always reproduce this problem doing the following steps:
I used the same email for both social and username/password signin but it's not required to be the same. I had other developer reproducing this with different emails.
PS: I can signin + logout multiple times with a email/password without any problems. It happens when we add social signin to the equation.
Below is the code used to reproduce the issue
// Launch web UI for social signin
fun signIn(activity: Activity, provider: AuthProvider): LiveData<Result<Boolean>> {
val lv = MutableLiveData<Result<Boolean>>()
// Launch cognito web social UI.
awsAuth.signInWithSocialWebUI(
provider,
activity,
{ result ->
if (result.isSignInComplete) {
lv.postValue(Result.Success(true))
}
},
{ error ->
val userCancelled = error.cause?.message == "user cancelled"
val errorCode = if (userCancelled) ErrorCode.USER_CANCELLED else ErrorCode.UNKNOWN
lv.postValue(Result.Error(AuthenticationException(errorCode)))
}
)
return lv
}
private suspend fun fetchAuthSession(): AuthSession {
return suspendCancellableCoroutine { cont ->
amplifyProxy.fetchAuthSession(
Consumer { result -> cont.resume(result) },
Consumer { error -> cont.resumeWithException(error) }
)
}
}
// Code used to signin a user with email/password strategy.
override suspend fun signInWithCredentials(credentials: Credentials): Result<Boolean> {
return suspendCancellableCoroutine { cont ->
awsAuth.signIn(
credentials.email.value,
credentials.password.value,
{
runBlocking {
try {
val session = fetchAuthSession()
val result = if (session.isSignedIn) {
// Here at step number 5, isSignedIn is true but we receive an error saying => "Your session has expired"
// and no tokens are available.
Result.Success(true)
} else Result.Error(RuntimeException("User not signedIn"))
cont.resume(result)
} catch (e: Exception) {
logError(e, credentials.email.value)
cont.resume(Result.Error(e))
}
}
},
{
Logger.logException(it)
cont.resume(Result.Error(it))
}
)
}
}
override suspend fun logout(): Result<Boolean> {
return suspendCancellableCoroutine { cont ->
awsAuth.signOut(
{
cont.resume(Result.Success(true))
},
{ error ->
Logger.logException(error)
cont.resume(Result.Error(error))
}
)
}
}
The code below is just for initial guidance, to help trace the problem, if it does not help please ignore it.
Tracing the calls, fetchAuthSession
goes to AwsMobileClient
->
AwsMobileClient. getUserStateDetails(final boolean offlineCheck)
calls _getTokens()
https://github.com/aws-amplify/aws-sdk-android/blob/a7d6794c965e56d9a019f26261c94a9ff1f19231/aws-android-sdk-mobile-client/src/main/java/com/amazonaws/mobile/client/AWSMobileClient.java#L1042
_getTokens(..)
method
https://github.com/aws-amplify/aws-sdk-android/blob/a7d6794c965e56d9a019f26261c94a9ff1f19231/aws-android-sdk-mobile-client/src/main/java/com/amazonaws/mobile/client/AWSMobileClient.java#L1788
After trying to get tokens AwsMobileClient. getUserStateDetails
enters line 1069 with a an exception
that says No cached session
https://github.com/aws-amplify/aws-sdk-android/blob/a7d6794c965e56d9a019f26261c94a9ff1f19231/aws-android-sdk-mobile-client/src/main/java/com/amazonaws/mobile/client/AWSMobileClient.java#L1069
You can see _getTokens(...)
calling userpool.getCurrentUser().getSession(..)
and it ends up at getCachedSession()
throwing CognitoNotAuthorizedException("User-ID is null")
.
Hope this helps to clarify the problem.
Hi @Sserra90
I had exactly the same problem. I managed to get out using the globalSignOut(true) option on my signout.
https://docs.amplify.aws/lib/auth/signOut/q/platform/android
Hope this helps
@falary1 Thanks, I'll try to reproduce the issue again and see it that fixes it. However for me it's not an option i don't want a global signout every time a user logs out.
Hi all, after the last comment i spent some time trying to debug this issue in depth and i believe i found what the problem is.
I think this issue is also suffering from the same problem https://github.com/aws-amplify/aws-sdk-android/issues/1469
Like i said in previous comment you can reproduce this using the following steps:
There must be a social signIn
in the mix to make this happen. By monitoring the changes to shared_prefs/CognitoIdentityProviderCache.xml
during every step above this is whats happening.
1- After the user signIn using hostedUI
the contents of the file are updated with idToken
, refreshToken
, accessToken
and LastAuthUser
2 - Users signs out, then the contents of the file are cleared. So far so good.
3 - Users signIn with username and password. Again the contents of the file are updated with idToken
, refreshToken
, accessToken
and LastAuthUser
4 - Users signs out. The contents of file are not cleared! only the LastAuthUser
entry is deleted. After this the user can no longer sign in until he clears app cache to delete the CognitoIdentityProviderCache.xml
, if he tries the following exception is raised:
W/AWSMobileClient: Tokens are invalid, please sign-in again.
java.lang.Exception: No cached session.
at com.amazonaws.mobile.client.AWSMobileClient$12.onFailure(AWSMobileClient.java:1818)
at com.amazonaws.mobileconnectors.cognitoauth.AuthClient.getSession(AuthClient.java:182)
at com.amazonaws.mobileconnectors.cognitoauth.Auth.getSession(Auth.java:674)
at com.amazonaws.mobile.client.AWSMobileClient._getHostedUITokens(AWSMobileClient.java:1821)
at com.amazonaws.mobile.client.AWSMobileClient.access$800(AWSMobileClient.java:161)
at com.amazonaws.mobile.client.AWSMobileClient$11.run(AWSMobileClient.java:1743)
at com.amazonaws.mobile.client.internal.InternalCallback.await(InternalCallback.java:115)
at com.amazonaws.mobile.client.AWSMobileClient.getTokens(AWSMobileClient.java:1717)
at com.amazonaws.mobile.client.AWSMobileClient.getUserStateDetails(AWSMobileClient.java:1024)
at com.amazonaws.mobile.client.AWSMobileClient.waitForSignIn(AWSMobileClient.java:903)
at com.amazonaws.mobile.client.AWSMobileClient$11.run(AWSMobileClient.java:1733)
at com.amazonaws.mobile.client.internal.InternalCallback.await(InternalCallback.java:115)
at com.amazonaws.mobile.client.AWSMobileClient.getTokens(AWSMobileClient.java:1699)
at com.example.tobi.androidapp.LoginActivity$3$1.run(LoginActivity.java:120)
at android.os.Handler.handleCallback(Handler.java:790)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
Why is this happening?
Looking at the code i think this is problem:
In AwsMobileClient._signOut(...)
method https://github.com/aws-amplify/aws-sdk-android/blob/6cf536fbbc0ec062b94ec62143482848b83d25e1/aws-android-sdk-mobile-client/src/main/java/com/amazonaws/mobile/client/AWSMobileClient.java#L1548 it checks if the hostedUI != null
and if it is calls hostedUI.signOut()
, because we did a sign in with hostedUI on the first step the code enters here. This method clears the LastAuthUser
from preferences file but keeps everything else.
After that
AwsMobileClient.signOut()
https://github.com/aws-amplify/aws-sdk-android/blob/6cf536fbbc0ec062b94ec62143482848b83d25e1/aws-android-sdk-mobile-client/src/main/java/com/amazonaws/mobile/client/AWSMobileClient.java#L1586
is called, and calls userPool.getCurrentUser().signOut()
however since LastAuthUser
was deleted before now the getCurrentUser()
returns a null user and the contents of the file are not cleared, we are now in an inconsistent state. After this the user cannot signIn
anymore.
Currently the fix that is working for me is to manually clear the contents of CognitoIdentityProviderCache.xml
in the Amplify signout method onSuccess callback. Ex:
amplify.signOut(
Action {
/**
* We need to manually clear local Amplify cache.
* See https://github.com/aws-amplify/amplify-android/issues/873
* for more information.
*/
AWSKeyValueStore(context, "CognitoIdentityProviderCache", true).clear()
cont.resume(Result.Success(true))
},
Consumer { error ->
Logger.logException(error)
cont.resume(Result.Error(error))
}
)
@falary1 i believe doing a globalSignOut
works because it goes into a different code flow and avoids this issue.
@jamesonwilliams It would be good if someone from Amplify team could reproduce the issue and confirm if this assumptions are correct. This a nasty issue because it makes the user unable to login again until he clears the app data or reinstall.
Amplify version 1.3.2 Authentication flow type is set to "USER_PASSWORD_AUTH"
@Sserra90 Hi,
Since my last comment, i tried to clear cache manually with no success (i wanted to avoid globalSignOut() too), and i finally achieved to refresh amplify cache by using
AWSMobileClient.getInstance().signOut();
and then,
AWSMobileClient.getInstance().refresh();
which i guess did the job by updating cache credentials.
I've read your post, and i think you're right about this issue. Your way to fix it is also working (this is exactly what i was looking for), and i will use it because this is more accurate i think.
Weird that not many of us talk about this ;)
Thanks !
Yes I'm seeing the same issue when using Amplify Flutter on Android, the issue is not happening on iOS. Any fixes on this?
This is important for Amplify Flutter because it hasn't implemented support for globalSignout
yet, and I do not want to use globalSignout
all the time.
Thanks!
Any updates on this issue?
This issue is now resolved with v1.17.8. Please follow the updated documentation to apply this fix :)
Hello,
I have the same issue even when I am using the new version of the library com.amplifyframework:aws-auth-cognito:1.25.0
(or version v1.17.8).
I have done everything according to documentation and this issue still persists for me. Can someone confirm that the issue is really fixed?
Thanks
Hey guys,
After an initial social sign-in, if I logout, I'm facing an issue where I can't sign back in, again.
Steps to reproduce
signInWithSocialWebUI
.It does not have to be the same account for both logins.
Sign-in with username/password code
An error is returned after calling
fetchAuthSession
:Sign-in returns success, but immediately after that, when fetching the auth session, it returns an error:
Fetch auth session code
After debugging, I can see the problem is raised in
_getToken()
->userpool.getCurrentUser().getSession()
->getCachedSession()
whereuserId == null
:After that i receive an exception saying:
If I clear app cache, then I'm able to sign-in again using a username/password. Otherwise, it gets stuck forever. It seems to be an inconsistency with local cache after sign-in + logout with social provider.
Amplify version 1.3.2 Authentication flow type is set to "USER_PASSWORD_AUTH"