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

Manually expire or invalidate tokens and get new issued. #696

Closed
grohj opened this issue Feb 11, 2019 · 24 comments
Closed

Manually expire or invalidate tokens and get new issued. #696

grohj opened this issue Feb 11, 2019 · 24 comments
Assignees
Labels
cognito Issues with the AWS Android SDK for Cognito feature-request Request a new feature pending-community-response Issue is pending response from the issue requestor

Comments

@grohj
Copy link

grohj commented Feb 11, 2019

State your question
We are using IdToken to identify user in our backend. The IdToken contains information like users name, etc. If user decides to change his personal information, this changes doesn't propagate into existing IdToken. Data is present in the token upon its refresh.

Is there a way to invalidate existing tokens, and force the pool to issue new one?
Btw logging out and loggin in again is out of question, because we are using passwordless login procedure.

Which AWS Services are you utilizing?
Cognito

Environment(please complete the following information):

  • SDK Version: 2.11.0
@mutablealligator mutablealligator added cognito Issues with the AWS Android SDK for Cognito question General question labels Feb 11, 2019
@minbi minbi added feature-request Request a new feature and removed question General question labels Feb 11, 2019
@minbi
Copy link
Contributor

minbi commented Feb 11, 2019

Hi @grohj ,

We don't currently support re-fetching the id token when it is not expired.
There are two approaches that come to mind.

  1. Maintain the personal information yourself and pass along this information to any relevant code flows.
  2. If you are issuing refresh tokens, you may try to clear the id token and access token from the SharedPreferences and attempt to refresh the tokens (forcing). This obviously breaks the abstraction that the SDKs provide.

I will check with the service team to see if there are any other flows available for you to use.

@minbi
Copy link
Contributor

minbi commented Feb 21, 2019

Hi @grohj ,

You will need to force refresh the tokens using the method in my previous post. We will investigate adding exposing this functionality in our clients.

@frankmuellr frankmuellr added the pending-community-response Issue is pending response from the issue requestor label Feb 21, 2019
@grohj
Copy link
Author

grohj commented Feb 22, 2019

Hi @minbi ,

I really appreciate your response. I used basically the first option you provided. The second one is hacky approach which I won't take my chances with.

Anyways, glad you are considering to add this feature, looking forward to see it :)

Thanks.

@palpatim palpatim removed the pending-community-response Issue is pending response from the issue requestor label Apr 18, 2019
@Mehdi-android
Copy link

Hi @grohj ,

We don't currently support re-fetching the id token when it is not expired.
There are two approaches that come to mind.

  1. Maintain the personal information yourself and pass along this information to any relevant code flows.
  2. If you are issuing refresh tokens, you may try to clear the id token and access token from the SharedPreferences and attempt to refresh the tokens (forcing). This obviously breaks the abstraction that the SDKs provide.

I will check with the service team to see if there are any other flows available for you to use.

Hello,
Can you please tell me in detail how to go forward with second approach.

Thanks

@minbi minbi removed their assignment Jun 18, 2019
@sachinavm12
Copy link

Hi @minbi,

Any update on this as it is a valid use case when using custom claims?

@desokroshan
Copy link
Contributor

@sachinavm12 At this point we do not have an update on this feature. I have added this to the #634 for tracking. We will post an update once the feature is released.

@CodeBreak524
Copy link

Hi, @desokroshan

Can you provide any new info about when this feature is going to be done?

Btw it seems that this feature is already done in iOS SDK and presented as clearSession() method for User identity. It clears cached session from memory and idToken and accessToken from preferences. It looks like smth like that should be good enough solution for this feature either.

@mangeshsambare
Copy link

Hi,
How can I get ID token forcefully even it is not expired.
Any updates on this issue??

@joeboyscout04
Copy link

Is this anything you'd consider accepting a pull request for? It's been blocking our development for quite a while, especially painful considering it's already present on iOS.

@hamen
Copy link

hamen commented Sep 21, 2021

As reference, I'm tracking our closed ticket #2637 here as well.

It's unfortunate that this is not prioritized and we can't have feature parity with the iOS SDK.

@LizDodion
Copy link

agree that this is unfortunate as it would be great to have a solution to this.

@jonreeve
Copy link

Note there's a (very fragile) workaround over on this related ticket, to do this by accessing a private field and 3 private functions. Would be so good, so appreciated, if that was exposed properly, stable, supported, etc. However for us poor saps trying to make this work in the meantime, that may be the only option for now 🤷

@frimfram frimfram self-assigned this Sep 27, 2021
@PS-MS
Copy link

PS-MS commented Oct 15, 2021

This is a very important feature to our app, currently if the user is added to a new Cognito group while logged in we have to ask the user to log out and back in to retrieve the new group setting.

@frimfram
Copy link

frimfram commented Nov 4, 2021

Hello all , here is a test that uses revokeTokens method of CognitoUser. are your use cases something similar?

As a reference, this is the revokeTokens implementation. Please let us know if this function would work for you or you would like a function with different behaviors. Thanks!

@PS-MS
Copy link

PS-MS commented Nov 4, 2021

Hi @frimfram,

This doesn't work for my use case, for me it is an attempt to support dynamic auth groups within DataStore.

My issue is that when a user is added to a new Cognito group their current token isn't updated with the new group, this is understandable, so to retrieve the new group I would like the login token to be revoked and a new one issued without the user needing to sign in again.

@frimfram
Copy link

frimfram commented Nov 4, 2021

Revoking tokens and issuing new one automatically in one function can lead to big security hole so we'll need to evaluate implication thoroughly. Here are some discussions on a related problem: aws-amplify/amplify-js#1213 (comment)

In the meantime, something like using "revokeTokens" to clean up the user session and calling "signIn" function and/or re-issuing your "IdToken" may work and lead to more secure result.

@PS-MS
Copy link

PS-MS commented Nov 5, 2021

The main issue for my use case is simply that a users current token doesn't reflect their real time cognito groups and signing out and back in or revoking and issuing a token is just a work around for that issue to give the user their real permissions.

It sounds like for me, and the others in this thread, we just need a way to update the information stored with the current token so that it matches any changes made to the back end data

@jonreeve
Copy link

jonreeve commented Nov 5, 2021

@frimfram Thanks but the request here is specifically to avoid signing the user out and the poor UX that leads to. As for security concerns, the thing being asked for is parity with a feature the iOS SDK already offers, so worth checking that out regarding those. Obviously caution is justified but perhaps their implementation could inform this one.

@frimfram
Copy link

frimfram commented Nov 5, 2021

@jonreeve sorry that it was not clear.
The parity with a feature in the iOS SDK already exists in Android SDK: The naming of the function is different - instead of User.clearSession (in iOS), there is User.revokeTokens and User.signOut (in Android). Please try revokeTokens and/or signOut and see if that works for you. The details of revokeTokens are in my previous post here:
#696 (comment)
The details of signOut (which calls clearCachedTokens) are here:

iOS does not support clearing and auto generation of session in one function (proactive refresh):
aws-amplify/amplify-swift#1179
Proactive refresh would easily lead to security hole so recommend clearing session and log in users again.

@jonreeve
Copy link

jonreeve commented Nov 8, 2021

@frimfram in the issue you linked to, there's this comment that describes using clearSession and then calling fetchAuthSession. As they note there, the documentation of clearSession says: "Remove the id and access token from the keychain, but keep the refresh token. Use this when you have updated user attributes and want to refresh the id and access tokens.". That's exactly what we're after here: clear the id and access token, not the refresh token. In the iOS version of the app we're working on, they simply call this function, and the next thing that uses it triggers it to refresh those tokens, and does not sign the user out, but does update the user attributes.

This is the implementation of this function on iOS for reference: https://github.com/aws-amplify/aws-sdk-ios/blob/main/AWSCognitoIdentityProvider/AWSCognitoIdentityUser.m#L1465-L1473

The clearCachedTokens function you linked, as you said, is called from signOut. It is actually very similar to the iOS clearSession function, but it also clears the refresh token. We're not interested in signing the user out just to refresh some attributes that have changed on the back-end about them.

revokeTokens appears to be something a bit more than that, actually issuing a request to the back-end to revoke them I guess? It doesn't look similar to the iOS function we're asking about in purpose or in implementation. Regardless, I tried calling it as you've advised, where we want this to happen, and I'm afraid it didn't seem to have any effect. I don't seem to get signed out, but also the user attributes are still outdated, and the ID and access tokens seem to have the same values before and after calling it.

What does currently work for us, for comparison, is this approach that currently requires reflection to access. What we're looking for is a function on the Android SDK to clear id + access token but NOT refresh token, so that the tokens (and thus the user attributes that have changed) will be refreshed upon next use, exactly as currently happens on the iOS SDK.

@jmcanache
Copy link

Hello Everyone. Is there any update on this subject? For the momento I'm applying the solution @minbi propose, with the clear manually of the idToken and accessToken from sharedPreferences and then forcing a refresh. But I don't know how dangerous is this.

@div5yesh
Copy link
Contributor

Please use the following as a workaround until we find a proper solution:

Set the refresh threshold higher than current expiration of idToken or accessToken to force a refresh. During the subsequent getTokens calls, the library will fetch new tokens as long as refreshToken is not expired.

CognitoIdentityProviderClientConfig.setRefreshThreshold(thresholdInMS); where thresholdInMS is the refresh threshold in milliseconds and if it is greater than the token expiration forces a token refresh request.

new Thread(() -> {
    try {
    CognitoIdentityProviderClientConfig.setRefreshThreshold(100000);
    AWSMobileClient.getInstance().getTokens();
    } catch (Exception e) {
        e.printStackTrace();
    }
}).start();

@tjleing
Copy link
Contributor

tjleing commented Apr 29, 2022

If the workaround does not work, please comment on this issue or open a new one.

@orcuns
Copy link

orcuns commented Jan 16, 2024

Please use the following as a workaround until we find a proper solution:

Set the refresh threshold higher than current expiration of idToken or accessToken to force a refresh. During the subsequent getTokens calls, the library will fetch new tokens as long as refreshToken is not expired.

CognitoIdentityProviderClientConfig.setRefreshThreshold(thresholdInMS); where thresholdInMS is the refresh threshold in milliseconds and if it is greater than the token expiration forces a token refresh request.

new Thread(() -> {
    try {
    CognitoIdentityProviderClientConfig.setRefreshThreshold(100000);
    AWSMobileClient.getInstance().getTokens();
    } catch (Exception e) {
        e.printStackTrace();
    }
}).start();

This workaround doesn't work. This threshold is not big enough to trigger for new AccessToken. Also, I can't set more than 1800000.
private static final long REFRESH_THRESHOLD_MAX = 1800 * 1000; CognitoIdentityProviderClientConfig.class:

 public static void setRefreshThreshold(long threshold) {
        if (threshold > REFRESH_THRESHOLD_MAX || threshold < REFRESH_THRESHOLD_MIN) {
            throw new CognitoParameterInvalidException(
                    String.format("The value of refreshThreshold must between %d and %d milliseconds",
                    REFRESH_THRESHOLD_MIN, REFRESH_THRESHOLD_MAX));
        }
        refreshThreshold = threshold;
    }

Is there anything I'm missing @div5yesh ?

isValidForThreshold still returns true because for example my accessTokenExpiresInMilliSeconds = 3432550

  public boolean isValidForThreshold() {
        try {
            if (idToken == null) {
                Log.w(TAG, "CognitoUserSession is not valid because idToken is null.");
                return false;
            }

            if (accessToken == null) {
                Log.w(TAG, "CognitoUserSession is not valid because accessToken is null.");
                return false;
            }

            final long currentTime = System.currentTimeMillis()
                    - SDKGlobalConfiguration.getGlobalTimeOffset() * SECS_CONVERSION;
            final long idTokenExpiresInMilliSeconds = idToken.getExpiration().getTime() - currentTime;
            final long accessTokenExpiresInMilliSeconds = accessToken.getExpiration().getTime() - currentTime;
            return (idTokenExpiresInMilliSeconds > CognitoIdentityProviderClientConfig.getRefreshThreshold()) &&
                    (accessTokenExpiresInMilliSeconds > CognitoIdentityProviderClientConfig.getRefreshThreshold());
        } catch (final Exception e) {
            return false;
        }
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cognito Issues with the AWS Android SDK for Cognito feature-request Request a new feature pending-community-response Issue is pending response from the issue requestor
Projects
None yet
Development

No branches or pull requests