Q:

Cognito User Pool: How to refresh Access Token Android

How do you refresh the access token using Cognito for Android? The documentation suggest the following (https://docs.aws.amazon.com/cognito/latest/developerguide/using-amazon-cognito-user-identity-pools-android-sdk.html):
// Implement authentication handler 
AuthenticationHandler handler = new AuthenticationHandler {
    @Override
    public void onSuccess(CognitoUserSession userSession) {
        // Authentication was successful, the "userSession" will have the current valid tokens
        // Time to do awesome stuff
    }

    @Override
    public void getAuthenticationDetails(final AuthenticationContinuation continuation, final String userID) {
        // User authentication details, userId and password are required to continue.
        // Use the "continuation" object to pass the user authentication details

        // After the user authentication details are available, wrap them in an AuthenticationDetails class
        // Along with userId and password, parameters for user pools for Lambda can be passed here
        // The validation parameters "validationParameters" are passed in as a Map<String, String>
        AuthenticationDetails authDetails = new AuthenticationDetails(userId, password, validationParameters);

        // Now allow the authentication to continue
        continuation.setAuthenticationDetails(authDetails);
        continuation.continueTask();
    }

    @Override
    public void getMFACode(final MultiFactorAuthenticationContinuation continuation) {
        // Multi-factor authentication is required to authenticate
        // A code was sent to the user, use the code to continue with the authentication

        // Find where the code was sent to
        String codeSentHere = continuation.getParameter()[0];

        // When the verification code is available, continue to authenticate
        continuation.setMfaCode(code);
        continuation.continueTask();
    }

    @Override
    public void authenticationChallenge(final ChallengeContinuation continuation) {
        // A custom challenge has to be solved to authenticate

        // Set the challenge responses

        // Call continueTask() method to respond to the challenge and continue with authentication.
    }

    @Override
    public void onFailure(final Exception exception) {
        // Authentication failed, probe exception for the cause

    }
};
user.getSession(handler);

Here is why this does not work. The user object which I am getting the Session for is no longer authenticated when the token expires. So retrieving the cached user via the below, will return null
CognitoUser user = userPool.getCurrentUser();

Because the above returns null, I try to get the user object by id
CognitoUser user = userPool.getUser(userId);

Which works perfectly, except that user is not authenticated and will fail during the following callback stage because the userID is null
@Override
public void getAuthenticationDetails(final AuthenticationContinuation continuation, final String userID) 

Only when I attempt this call before the token expires does this work, and I can receive a new access token. But how to do this after the token has expired? Any help on this would be appreciated. Thanks in advance

A:

When you call getSession(...) - to get tokens - and if the cached tokens have expired, the SDK will automatically refresh tokens (as long as the refresh token has not expired). If the refresh token too has expired, then getAuthenticationDetails(...) is invoked because now the user credentials (username, password, etc) are required to get new set of tokens. It should not matter how you get the user object, i.e. through getCurrentUser() or getUser(...) methods, as long as there are valid cached tokens or if the tokens can be refreshed, you will get valid tokens with getSession(...).
Retry with the latest SDK (ver 2.3.1).

