Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Misleading exception thrown when token refresh failed due to network error #2806

Closed
1 task done
almosr-mikapaytech opened this issue May 7, 2024 · 15 comments
Closed
1 task done
Labels
auth Related to the Auth category/plugins bug Something isn't working

Comments

@almosr-mikapaytech
Copy link

almosr-mikapaytech commented May 7, 2024

Before opening, please confirm:

Language and Async Model

Kotlin

Amplify Categories

Authentication

Gradle script dependencies

// Put output below this line
aws_amplify_version = '2.16.1'
implementation "com.amplifyframework:aws-auth-cognito:$aws_amplify_version"
implementation "com.amplifyframework:aws-analytics-pinpoint:$aws_amplify_version"
implementation "com.amplifyframework:rxbindings:$aws_amplify_version"

Environment information

# Put output below this line
------------------------------------------------------------
Gradle 8.5
------------------------------------------------------------

Build time:   2023-11-29 14:08:57 UTC
Revision:     28aca86a7180baa17117e0e5ba01d8ea9feca598

Kotlin:       1.9.20
Groovy:       3.0.17
Ant:          Apache Ant(TM) version 1.10.13 compiled on January 4 2023
JVM:          17.0.9 (Oracle Corporation 17.0.9+11-LTS-201)
OS:           Windows 11 10.0 amd64

Please include any relevant guides or documentation you're referencing

No response

Describe the bug

When identity token expired and refresh token cannot be used due to network error then Amplify throws an unrelated error:

Caused by: InvalidUserPoolConfigurationException{message=The user pool configuration is missing or invalid., cause=null, recoverySuggestion=Please check the user pool configuration in your amplifyconfiguration.json file.}
 at com.amplifyframework.auth.cognito.RealAWSCognitoAuthPlugin$getCurrentUser$1$1.invokeSuspend(RealAWSCognitoAuthPlugin.kt:1789)
 at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
 at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:108)
 at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:584)
 at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:793)
 at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:697)
 at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:684)

It is possible to recover from this situation when network access is restored.

Reproduction steps (if applicable)

  1. Sign in using Amplify
  2. Wait until identity token expires (or adjust the local time on the device).
  3. Disable network (e.g. turn on aeroplane mode).
  4. Start the app and try to fetch the user session.

Code Snippet

// Put your code below this line.
RxAmplify.Auth.fetchAuthSession()
  .subscribe({ Log.d("Session fetch", "Success") }, { error -> Log.e("Session fetch", "Fetch failed", error) })

Log output

// Put your logs below this line


amplifyconfiguration.json

No response

GraphQL Schema

// Put your schema below this line

Additional information and screenshots

No response

@github-actions github-actions bot added the pending-triage Issue is pending triage label May 7, 2024
@yuhengshs yuhengshs added bug Something isn't working auth Related to the Auth category/plugins and removed pending-triage Issue is pending triage labels May 7, 2024
@yuhengshs
Copy link
Contributor

Hi @almosr-mikapaytech ,

Thanks for reporting this issue, our team will take a look and post once we have an update

@joon-won
Copy link
Member

joon-won commented May 7, 2024

Hi @almosr-mikapaytech, thank you for providing the code snippet, and the steps. I've followed the steps to trigger fetchAuthSession() after changing the system date to few days later, disconnecting the local environment from the internet. Unfortunately, I was not able to replicate the issue (InvalidUserPoolConfigurationException).

If you can, could you consider providing us Verbose level log with Amplify.addPlugin(AndroidLoggingPlugin(LogLevel.VERBOSE))

@almosr-mikapaytech
Copy link
Author

Hi @joon-won,
I added that log plugin with verbose level, but there are no more logs coming from Amplify than before. Is there any other configuration I should add to turn on the verbose mode?

@joon-won
Copy link
Member

joon-won commented May 8, 2024

Thank you @almosr-mikapaytech, with Verbose turned on you will be able to catch something like RefreshUserPoolTokens Sending event ThrowError or Auth State Change from AWSCognitoAuthPlugin which will help us better understand what's going on. I've tried another run today but was not able to replicate your issue. On my end I'm getting UnknownException due to lost internet connection.

Could you share your AWSCognitoAuthSession Result after removing sensitive information from it?

@almosr-mikapaytech
Copy link
Author

@joon-won I have made a mistake in the bug report, mixed up the chained calls.
While I was trying to find out the returned session I found that instead of fetchAuthSession() this error is coming from RxAmplify.Auth.currentUser that is called before the session is fetched.

After reversed the order of the calls (so session is fetched first) I get back this session:

AWSCognitoAuthSession(isSignedIn=false, identityIdResult=AuthSessionResult{value=null, error=NotAuthorizedException{message=Failed since user is not authorized., cause=NotAuthorizedException(message=Token is not from a supported provider of this identity pool.), recoverySuggestion=Please sign in and reattempt the operation.}, type=FAILURE}, awsCredentialsResult=AuthSessionResult{value=null, error=NotAuthorizedException{message=Failed since user is not authorized., cause=NotAuthorizedException(message=Token is not from a supported provider of this identity pool.), recoverySuggestion=Please sign in and reattempt the operation.}, type=FAILURE}, userSubResult=AuthSessionResult{value=null, error=NotAuthorizedException{message=Failed since user is not authorized., cause=NotAuthorizedException(message=Token is not from a supported provider of this identity pool.), recoverySuggestion=Please sign in and reattempt the operation.}, type=FAILURE}, userPoolTokensResult=AuthSessionResult{value=null, error=NotAuthorizedException{message=Failed since user is not authorized., cause=NotAuthorizedException(message=Token is not from a supported provider of this identity pool.), recoverySuggestion=Please sign in and reattempt the operation.}, type=FAILURE})

In this situation the app won't recover even after the network is working again. Refresh token should still be valid, but as it seems some other error blocks the refresh.

@joon-won
Copy link
Member

joon-won commented May 9, 2024

No worries @almosr-mikapaytech, seems like the error message is now more relevant. If the app won't recover with fetchAuthSession() after the network recovers, have you tried using forceRefresh option?

AuthFetchSessionOptions options = AuthFetchSessionOptions.builder().forceRefresh(true).build();

RxAmplify.Auth.fetchAuthSession(options)
                                .subscribe(
                                    { result -> Log.i(moduleLoggerCode, "Success\n$result") },
                                    { error -> Log.e(moduleLoggerCode, "Error\n$error") })

with forceRefresh you can force refresh the internal session

@almosr-mikapaytech
Copy link
Author

@joon-won Thank you for the response.

This is what I tried:

        RxAmplify.Auth.fetchAuthSession().flatMap {
            (it as AWSCognitoAuthSession).accessToken?.let { Single.just(it) }
                ?: RxAmplify.Auth.fetchAuthSession(
                    AuthFetchSessionOptions.builder().forceRefresh(true).build()
                ).map {
                    (it as AWSCognitoAuthSession).accessToken ?: Exception("User token was not provided")
                }
        }

Unfortunately, forcing the refresh does not resolve the issue. I still get back the same session error in the forced response:

AWSCognitoAuthSession(isSignedIn=false, identityIdResult=AuthSessionResult{value=null, error=NotAuthorizedException{message=Failed since user is not authorized., cause=NotAuthorizedException(message=Token is not from a supported provider of this identity pool.), recoverySuggestion=Please sign in and reattempt the operation.}, type=FAILURE}, awsCredentialsResult=AuthSessionResult{value=null, error=NotAuthorizedException{message=Failed since user is not authorized., cause=NotAuthorizedException(message=Token is not from a supported provider of this identity pool.), recoverySuggestion=Please sign in and reattempt the operation.}, type=FAILURE}, userSubResult=AuthSessionResult{value=null, error=NotAuthorizedException{message=Failed since user is not authorized., cause=NotAuthorizedException(message=Token is not from a supported provider of this identity pool.), recoverySuggestion=Please sign in and reattempt the operation.}, type=FAILURE}, userPoolTokensResult=AuthSessionResult{value=null, error=NotAuthorizedException{message=Failed since user is not authorized., cause=NotAuthorizedException(message=Token is not from a supported provider of this identity pool.), recoverySuggestion=Please sign in and reattempt the operation.}, type=FAILURE})

@vincetran
Copy link
Member

Hi @almosr-mikapaytech, can you provide your amplifyconfiguration.json file so we can see how your stack is configured? And to confirm the exact conditions for this issue:

  • ID Token has expired
  • Refresh Token is still VALID
  • Network is down (e.g. airplane mode)
  • fetchAuthSession()is then called

I ask because we have a couple similar issues for those exact conditions (e.g. #2725 and #2783) but the exception encountered there don't match your exception. (UnknownHostException vs your NotAuthorizedException and InvalidUserPoolConfigurationException)

The only notable difference is also that you're using RxAmplify whereas they're not. Just as another troubleshooting tool, can you try making that call using the Kotlin library instead to see if you see the same error?

@vincetran vincetran added the pending-community-response Issue is pending response from the issue requestor label May 10, 2024
@almosr-mikapaytech
Copy link
Author

Hi @vincetran,

* ID Token has expired
* Refresh Token is still VALID
* Network is down (e.g. airplane mode)
* fetchAuthSession() is then called

Yes, these are all the conditions. Refresh token is valid for 365 days in our setup, so it must be valid 2 days later.

To make things interesting, I tried to reproduce this issue today to test what happens when I call the standard method instead of the RxAmplify. While it was constantly happening on Friday, it did not happen even once today. I tested it with the exact same steps, always started with an app re-install to make sure nothing is left.

Just to be clear: there are two , potentially separate issues mentioned in this ticket. One is the original issue that was reported for RxAmplify.Auth.currentUser, that is still valid (misleading exception).
What I was not able to reproduce is the other error thrown by RxAmplify.Auth.fetchAuthSession. Today it was always a correct UnknownHostException exception and when the network came back then the token was refreshed correctly.

So, I am puzzled, not sure what can we do about the issue. My gut feeling is that it has something to do with time or date.
We are located in New Zealand, quite often we discover issues related to date shifting (due to the 12-13 hours timezone difference).

Anyway, for your reference, here is the Amplify config file we are using. There is nothing special in it as far as I can tell.
amplifyconfiguration_redacted.json

This is the user pool config:
user_pool_settings

Please let me know if I could do anything else.
We are quite nervous about this issue, our product is going live within a few days. While other apps might just ask the user to log in again, authentication in our product takes much more effort from the user.

@github-actions github-actions bot removed the pending-community-response Issue is pending response from the issue requestor label May 13, 2024
@tylerjroach
Copy link
Member

tylerjroach commented May 13, 2024

Hi @almosr-mikapaytech

Whether you are using standard Amplify callbacks, Kotlin Coroutines, or RxJava, each of these strategies should yield the same error messages. RxJava and Kotlin Coroutines simply wrap around the callback approach. The code paths do not differ. I think we can safely rule out the strategy (callbacks/rxjava,coroutines) used to call Amplify.

Error 1: "The user pool configuration is missing or invalid."

I think this is a bad message on our part. Auth.getCurrentUser calls fetchAuthSession() internally. If that call fails (ex: bad network), I think the above message will get triggered, which is not the correct message to display. This isn't the real message coming from the internal fetchAuthSession call.

Error 2: "NotAuthorizedException(message=Token is not from a supported provider of this identity pool.)"

This is likely the failure happening inside that internal fetchAuthSession call, as well as the message you are seeing if you call fetchAuthSession before getCurrentUser.

The important thing to note on this issue: "Token is not from a supported provider of this identity pool." is that this did not come from a locally constructed error message. This message is not hardcoded in Amplify and could have only come from the Cognito service.

With this context in mind, can you share a bit more about the authentication methods that are available in your application?

I see "ADMIN_NO_SRP_AUTH" and "USER_PASSWORD_AUTH", but do have "ALLOW_REFRESH_TOKEN_AUTH" as an authentication flow in the Cognito console? It says its always enabled, but its odd that my Auth apps show the option as always selected where I don't see it in yours.

Next, do you have any social sign ins? I see that you have hosted UI authentication configured in your application. Do you have multiple login flows in your application (ex: native and hosted ui)?

I see that you have token revocation enabled. Do you have any service side processes that could be revoking token access, or signing out with global sign out = "true". This could revoke tokens on other devices.

"Token is not from a supported provider of this identity pool." is a very specific error coming from the service so we should try and focus on what is causing this exact message.

@tylerjroach tylerjroach added the pending-community-response Issue is pending response from the issue requestor label May 13, 2024
@almosr-mikapaytech
Copy link
Author

Hi @tylerjroach,

The app uses user-password authentication method only, the user is created programmatically on service side and one time password is used for authentication. Direct sign by using with email or any other method (e.g. social sign in) is not available.

In the console the option for ALLOW_REFRESH_TOKEN_AUTH is disabled:
image
I am not sure why and also not sure whether this method would be required or not. The purpose of this method is unclear from documentation.

I asked the backend devs regarding forced sign out, they told me there is no such flow implemented currently.
The app never calls the token revoke method, only sign out before signing in with the new credentials.

Would it be possible to find out from service-side logs why Cognito sent back that specific error?

@github-actions github-actions bot removed the pending-community-response Issue is pending response from the issue requestor label May 14, 2024
@tylerjroach
Copy link
Member

@almosr-mikapaytech How many times have you seen this issue? I would triple check all of the values on the console side to make sure they match what is being used in amplifyconfiguration.

In researching what this error message means, I came across "This issue usually occurs if the app client used for authenticating the user is different from the app client configured with the identity pool. You may confirm this by checking if the aud value in the identity token is different from what's configured in your identity pool."

@rBressanS
Copy link

Hi @tylerjroach, I'm a backend developer on the @almosr-mikapaytech team. After enabling the cloud trail for the cognito and management events and with your comments on this thread, we could identify that the problem was caused by the fact that one of our User Pools was not registered as a valid identity provider for our Identity Pool.

It is still weird that Identity Pool errors revoked User Pool tokens, but the issue is solved.

@tylerjroach
Copy link
Member

Great to hear, thank you for following up to let us know the issue. This helps us troubleshoot future investigations!

Copy link
Contributor

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
auth Related to the Auth category/plugins bug Something isn't working
Projects
None yet
Development

No branches or pull requests

6 participants