Aws-sdk-android: Tokens are invalid, please sign-in again after call AWSMobileClient.getInstance().getTokens(callback)

Created on 5 Apr 2019  路  16Comments  路  Source: aws-amplify/aws-sdk-android

Describe the bug
I have already signed in and then I kill app and open app again.
In my plash screen I call API AWSMobileClient.getInstance().initialize() and check the user state is "SIGNED_IN".
After that I go to next step, call my backend API which needs token using AWSMobileClient.getInstance().getTokens(new Callback()) after i call that API. I got user state is " SIGNED_OUT_USER_POOLS_TOKENS_INVALID" and This call blocked the thread forever don't return token or any error.

I know that the token will expire after 1 hour but I have already signed in. Just kill my app and open app again How can i got SIGNED_OUT_USER_POOLS_TOKENS_INVALID after call get token.

I resolved it by add UserStateListener after getting SIGNED_OUT_USER_POOLS_TOKENS_INVALID i will sign in again but should I do that every time I kill app and open again ?

To Reproduce

Code and logs

`My code in plash screen: 
AWSMobileClient.getInstance().initialize(getApplicationContext(), new Callback<UserStateDetails>() {
                    @Override
                    public void onResult(UserStateDetails userStateDetails) {
                        Log.i("MYLOG", "Result: " + userStateDetails.getUserState());
                        initializeSingletonClass();

                        if (userStateDetails.getUserState() == UserState.SIGNED_IN) {
                            routeToAppropriatePage(ActMain.class);
                        } else {
                            routeToAppropriatePage(ActLoginOption.class);
                        }
                    }

                    @Override
                    public void onError(Exception e) {
                        Log.e(TAG, "MYLOG", e);
                        routeToAppropriatePage(ActLoginOption.class);
                    }
                }
        );
        AWSMobileClient.getInstance().addUserStateListener(new UserStateListener() {
            @Override
            public void onUserStateChanged(UserStateDetails details) {
                switch (details.getUserState()) {
                    case GUEST:
                        Log.i("MYLOG", "user is in guest mode");
                        break;
                    case SIGNED_OUT:
                        Log.i("MYLOG", "user is signed out");
                        break;
                    case SIGNED_IN:
                        Log.i("MYLOG", "user is signed in");
                        break;
                    case SIGNED_OUT_USER_POOLS_TOKENS_INVALID:
                        Log.i("MYLOG", "need to login again");
                        break;
                    case SIGNED_OUT_FEDERATED_TOKENS_INVALID:
                        Log.i("MYLOG", "user logged in via federation, but currently needs new tokens");
                        break;
                    default:
                        Log.e("MYLOG", "unsupported");
                }
            }
        });

I put it onResume function 

My code when i call get token: 
    protected Single<String> getToken() {
        return Single.create((subscribe) -> {
            AWSMobileClient.getInstance().getTokens(new Callback<Tokens>() {
                @Override
                public void onResult(Tokens result) {
                    Log.d(TAG, "getTokens onResult: access");
                    subscribe.onSuccess(result.getAccessToken().getTokenString());
                }

                @Override
                public void onError(Exception e) {
                    Log.d(TAG, "getTokens onError: " + e);
                    subscribe.onError(e);
                }
            });
        });
    }
log: 
when i go to plash screen: 
2019-04-05 16:11:23.495 31573-31784/ I/MYLOG: Result: SIGNED_IN
2019-04-05 16:11:23.674 31573-31842/ I/MYLOG: user is signed in
after i call get token: 
2019-04-05 16:11:23.495 31573-31784/ I/MYLOG: Result: SIGNED_IN
2019-04-05 16:11:23.674 31573-31842/ I/MYLOG: user is signed in
2019-04-05 16:11:24.369 31573-31916/ I/MYLOG: need to login again`

Environment Information (please complete the following information):

  • AWS Android SDK Version: 2.13.0
  • Device: Samsung, xiaomi, Redmi
  • Android Version: 7.1.1, 8.1.0

I'm waiting for your feedback.
Thanks

AWSMobileClient Bug Needs Info from Requester closing-soon-if-no-response

Most helpful comment

The HostedUI (CognitoAuth) object has a lifecycle that starts from showSignIn and ends at signOut. However when getTokens() is called after initialize, the hostedUI object is null.

There are two objects for hostedUI (one through awsconfiguration.json and other through code). The AWSMobileClient.initialize always constructs hostedUI through awsconfiguration.json and does not construct the hostedUi object through code.

We are looking into a fix where we could construct one object for hostedUI during initialize which reads off the awsconfiguration.json and is useful for getTokens to work. When showSignIn is called, the same hostedUI object will be mutated to work for a signIn operation. The signOut method should not deallocate the hostedUI object.

I am working on the fix and testing for HostedUI through AWSMobileClient.

All 16 comments

@tvanmanh There are significant bugs in 2.13.0 (and 2.12.x) with token management if using AWSMobileClient drip in UI, and as as a result the AWSMobieClient drop in UI will not refresh tokens properly and other related issues. I was able to get it working in 2.13.1.

You wrote: "I resolved it by add UserStateListener after getting SIGNED_OUT_USER_POOLS_TOKENS_INVALID i will sign in again but should I do that every time I kill app and open again ?"

I do exactly that in my code taken from the sample code and this should work in 2.13.1.

                switch (userStateDetails.getUserState()){
                    case SIGNED_IN:
                        Log.i("onUserStateChanged", "SIGNED_IN: ");
                        initializeAndLoadData();
                        break;
                    case SIGNED_OUT:
                        Log.i("onUserStateChanged", "SIGNED_OUT:");
                        showSignIn();
                        break;
                    case SIGNED_OUT_USER_POOLS_TOKENS_INVALID:
                        Log.i("onUserStateChanged", "SIGNED_OUT_USER_POOLS_TOKENS_INVALID: need to login again.");
                        showSignIn();
                        break;
                    case SIGNED_OUT_FEDERATED_TOKENS_INVALID:
                        Log.i("onUserStateChanged", "SIGNED_OUT_FEDERATED_TOKENS_INVALID: need to login again.");
                        showSignIn();
                        break;
                    case GUEST:
                        Log.i("onUserStateChanged", "GUEST.");
                        showSignIn();
                        break;
                    default:
                        Log.i("onUserStateChanged", "unsupported, default.");
                        showSignIn();
                        break;
                }
            }
        };

where showSignIn() is calls

AWSMobileClient.getInstance().showSignIn(
                        MainActivity.this,
                        SignInUIOptions.builder()
                                .nextActivity(MainActivity.class)
                                .canCancel(false)
                                .build(),
                        new Callback<UserStateDetails>() {
                            @Override
                            public void onResult(UserStateDetails result) {
                                Log.d(TAG, "showSignIn() onResult() result: userState: " + result.getUserState());
                                switch (result.getUserState()) {
                                    case SIGNED_IN:
                                        Log.d(TAG, "showSignIn() callback: SIGNED_IN logged in!");
                                        initializeAndLoadData();
                                        break;
                                    case SIGNED_OUT:
                                        Log.d(TAG, "showSignIn() callback onResult: SIGNED_OUT ");
                                        break;
                                    case SIGNED_OUT_FEDERATED_TOKENS_INVALID:
                                        Log.d(TAG, "showSignIn() callback onResult: SIGNED_OUT_FEDERATED_TOKENS_INVALID");
                                        break;
                                    case SIGNED_OUT_USER_POOLS_TOKENS_INVALID:
                                        Log.d(TAG, "showSignIn() callback onResult: SIGNED_OUT_USER_POOLS_TOKENS_INVALID");
                                        break;
                                    case GUEST:
                                        Log.d(TAG, "showSignIn() callback onResult: GUEST");
                                        break;
                                    case UNKNOWN:
                                        Log.d(TAG, "showSignIn() callback onResult: UNKNOWN");
                                        break;
                                    default:
                                        Log.d(TAG, "showSignIn() callback onResult: default; Should not be possible.");
                                        break;
                                }
                            }

I hope this helps as you wait for an official response from the AWS team.

@BillBunting Thanks a lot for your help.

@BillBunting Thanks!

It's worth noting that the initialize() function returns the user state as SIGNED_IN even though getCurrentUserState() returns SIGNED_OUT_USER_POOLS_TOKENS_INVALID!

So make sure to call getCurrentUserState().


EDIT: If anyone using flutter came over here, the flutter_cognito_plugin has integrated the workaround for this inside the initialize() function. You just need to upgrade to 0.0.9, and you should be good to go!

I'm facing a similar issue
Here are my steps to reproduce it:

1.- Initialize AWSMobileClient

 AWSMobileClient.getInstance().initialize(this, object:Callback<UserStateDetails> {
            override fun onResult(result: UserStateDetails?) {
                //Timber.d("Initialize AWSMobileClient, User State: ${result?.userState}")
            }

            override fun onError(exception: Exception?) {
               // Timber.e(exception, "Error Initialization AWSMobileClient")
            }
        })

2.- Sign in users using hosted UI:

 AWSMobileClient.getInstance().showSignIn(this, signInUIOptions, object : Callback<UserStateDetails> {
                override fun onResult(details: UserStateDetails) {
                    Log.d("TEST", "onResult: " + details.userState)
                }
                override fun onError(e: Exception) {
                    Log.e("TEST", "onError: ", e)
                }
            })

3.- After a successfull sign in, close the app

3.- Open the app again

AWSMobileClient.getInstance().initialize() says that the userState is SIGNED_IN, but fails to retrieve the tokens:

Tokens are invalid, please sign-in again.
    java.lang.NullPointerException: Attempt to invoke virtual method 'void com.amazonaws.mobileconnectors.cognitoauth.Auth.setAuthHandler(com.amazonaws.mobileconnectors.cognitoauth.handlers.AuthHandler)' on a null object reference
        at com.amazonaws.mobile.client.AWSMobileClient._getHostedUITokens(AWSMobileClient.java:1645)
        at com.amazonaws.mobile.client.AWSMobileClient.access$900(AWSMobileClient.java:163)
        at com.amazonaws.mobile.client.AWSMobileClient$9.run(AWSMobileClient.java:1576)
        at com.amazonaws.mobile.client.internal.InternalCallback.await(InternalCallback.java:115)
        at com.amazonaws.mobile.client.AWSMobileClient.getTokens(AWSMobileClient.java:1550)
        at com.amazonaws.mobile.client.AWSMobileClient.getUserStateDetails(AWSMobileClient.java:1028)
        at com.amazonaws.mobile.client.AWSMobileClient$5.run(AWSMobileClient.java:828)
        at com.amazonaws.mobile.client.AWSMobileClient$5.run(AWSMobileClient.java:825)
        at com.amazonaws.mobile.client.internal.ReturningRunnable.await(ReturningRunnable.java:31)
        at com.amazonaws.mobile.client.AWSMobileClient.currentUserState(AWSMobileClient.java:807)
        at es.aiwin.games.migo.presentation.initial.InitialActivity.onResume(InitialActivity.kt:78)
        at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1355)
        at android.app.Activity.performResume(Activity.java:7117)
        at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3556)
        at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3621)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2862)
        at android.app.ActivityThread.-wrap11(Unknown Source:0)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1589)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        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)

I have debugged the SDK and the issue is that hostedUI property of AWSMobileClient instance is null. So calling private void _getHostedUITokens(final Callback<Tokens> callback) throws a null pointer exception. It seems that hostedUI is only initialized when showSignIn method is called. This explain why the first time the SDK works fine (showSignIn called to sign in the user) , and why fails when opening the app again (showSignIn not called because the user is already signed in).

I have looked another issues,and this https://github.com/aws-amplify/aws-sdk-android/issues/888 appears to be the same.

It's a very serious bug, that has not been resolved in a long time, so I think that should be resolved as soon as posible. (In my case, our company can not implement SAML login without this issue solved)

@JesusMartinAlonso Thanks for reporting the error. I will take a look at it and get back to you. r

I am working on this issue and will have an update when the fix is released. Thank you for the patience.

The HostedUI (CognitoAuth) object has a lifecycle that starts from showSignIn and ends at signOut. However when getTokens() is called after initialize, the hostedUI object is null.

There are two objects for hostedUI (one through awsconfiguration.json and other through code). The AWSMobileClient.initialize always constructs hostedUI through awsconfiguration.json and does not construct the hostedUi object through code.

We are looking into a fix where we could construct one object for hostedUI during initialize which reads off the awsconfiguration.json and is useful for getTokens to work. When showSignIn is called, the same hostedUI object will be mutated to work for a signIn operation. The signOut method should not deallocate the hostedUI object.

I am working on the fix and testing for HostedUI through AWSMobileClient.

This has been merged and will go into our next release.

A fix has been released in version 2.15.2 of the SDK. Please upgrade and verify.

This issue has been automatically closed because of inactivity. Please open a new issue if are still encountering problems.

Still seeing this on 2.15.2, on initialize it will tell me a user is signed in "result.getUserState().equals(UserState.SIGNED_IN)", then later on when I try to getTokens() it will say "AWSMobileClient: waitForSignIn: userState:SIGNED_OUT_USER_POOLS_TOKENS_INVALID in the console".

Also tested on 2.16.0, immediately after it tells me UserState.SIGNED_IN it fails on getTokens() with "SIGNED_OUT_USER_POOLS_TOKENS_INVALID". Makes no sense whatsoever.

Getting the same issue as @rbarbish

Getting the same issues @desokroshan for 2.15.2

Getting this in 2.16.2 same as @rbarbish. I'm not using HostedUI but calling signIn manually. Both initialize and getUserState() return SIGNED_IN, but a call to getTokens() immediately afterwards throws an exception: "Tokens are invalid, please sign-in again."

I also get the same error as @rbarbish. I am using the newest version (2.16.+).
Any news about the issue?

News here?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

cmbaykal picture cmbaykal  路  4Comments

logo17 picture logo17  路  3Comments

chorniyn picture chorniyn  路  3Comments

yairkukielka picture yairkukielka  路  3Comments

mockturtl picture mockturtl  路  4Comments