Giter Club home page Giter Club logo

Comments (31)

motoko89 avatar motoko89 commented on June 15, 2024 6

This is living proof the AWS team loves the .NET SDK more than any other languages! Probably will be fixed in 3 years

from aws-sdk-net-extensions-cognito.

RidhwanDev avatar RidhwanDev commented on June 15, 2024 4
   private void EnsureUserAuthenticated()
        {
            if (SessionTokens == null || !SessionTokens.IsValid())
            {
                throw new NotAuthorizedException("User is not authenticated.");
            }
        }
public CognitoUserSession SessionTokens
{
......
        public bool IsValid()
             {
                    DateTime currentTimeStamp = DateTime.Now;

                     return (currentTimeStamp.CompareTo(ExpirationTime) < 0);
             }
}

The 'expirationTime' we pass in is literally compared to the current time before it even attempts to authenticate.

EnsureUserAuthenticated(); is still a valid call to make in this function, we just need to be passing the expirationTime of the RefreshToken rather than the one for the 1 hour token.

from aws-sdk-net-extensions-cognito.

ddiimmiittaarr avatar ddiimmiittaarr commented on June 15, 2024 3

@ assyadh

Awesome!!!
I took like more than a year !!!!

Finger crossed for 2021

from aws-sdk-net-extensions-cognito.

peachwyss avatar peachwyss commented on June 15, 2024 2

@jeffreythomasprice I have the same issue, using DateTime.Now.AddHours(1)) seems to work-around the issue. But I also think this is a bug.

from aws-sdk-net-extensions-cognito.

RidhwanDev avatar RidhwanDev commented on June 15, 2024 2

Yeah, After a few months of having this Issue I think I know why it hasn't been fixed yet. It seems as though it was intended to work this way but the issue comes with a badly named parameter.

The reason DateTime.Now.AddHours(1) works is because that is doing the check against expiration time. I'm guessing we've all written something to check if the users 30 days are over before even getting to this function call so we will never make the call to refresh the token if their refresh token should be expired anyway.

public CognitoUserSession(string idToken, string accessToken, string refreshToken, DateTime issuedTime, DateTime expirationTime);

We're passing expirationTime as the token expiration time. However when refreshing the token, I think this should be passing in the Expiration Time of the RefreshToken.

I've changed this

user.SessionTokens = new CognitoUserSession(
	session.IdToken,
	session.AccessToken,
	session.RefreshToken,
	session.IssuedTime,
	session.TokenExpiresServer
);

into this

user.SessionTokens = new CognitoUserSession(
	session.IdToken,
	session.AccessToken,
	session.RefreshToken,
	session.IssuedTime,
        session.RefreshTokenExpiresServer
);

My RefreshTokenExpiresServer is set to be 25 days from when the user gets authenticated. This is what I think is the issue here is anyway. @jeffreythomasprice @sstevenkang @curtisshipley

This has fixed the issue for me.

from aws-sdk-net-extensions-cognito.

assyadh avatar assyadh commented on June 15, 2024 2

Hi everyone,

I'll have a look at this shortly and will narrow down the issue.

H

from aws-sdk-net-extensions-cognito.

philipogorman avatar philipogorman commented on June 15, 2024 2

Here is the code we use to refresh:
`

    public async Task<SignInContext> RefreshToken(string idToken, string accessToken, String refreshToken, DateTime issued, DateTime expires)
    {
        try
        {
            var provider = new AmazonCognitoIdentityProviderClient(new AnonymousAWSCredentials(), RegionEndpoint);

            CognitoUserPool userPool = new CognitoUserPool(PoolId, ClientId, provider);
            CognitoUser user = new CognitoUser("", ClientId, userPool, provider);

            // The  "Refresh token expiration (days)" (Cognito->UserPool->General Settings->App clients->Show Details) is the
            // amount of time since the last login that you can use the refresh token to get new tokens.
            // After that period the refresh will fail
            // Using DateTime.Now.AddHours(1) is a workaround for https://github.com/aws/aws-sdk-net-extensions-cognito/issues/24
            user.SessionTokens = new CognitoUserSession(idToken, accessToken, refreshToken, issued, DateTime.Now.AddHours(1));

            AuthFlowResponse context = await user.StartWithRefreshTokenAuthAsync(new InitiateRefreshTokenAuthRequest
            {
                AuthFlowType = AuthFlowType.REFRESH_TOKEN_AUTH
            })
            .ConfigureAwait(false);

            return new SignInContext(CognitoResult.Ok)
            {
                IdToken = context.AuthenticationResult?.IdToken,
                AccessToken = context.AuthenticationResult?.AccessToken,
                TokenIssued = user.SessionTokens.IssuedTime,
                Expires = user.SessionTokens.ExpirationTime,
                SessionId = context.SessionID
            };
        }
        catch (NotAuthorizedException ne)
        {
            //https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-with-identity-providers.html
            // refresh tokens will expire - user must login manually every x days (see user pool -> app clients -> details)
            return new SignInContext(CognitoResult.RefreshNotAuthorized) { ResultMessage = ne.Message };
        }
        catch (WebException webEx)
        {
            // we get a web exception when we cant connect to aws - means we are offline
            return new SignInContext(CognitoResult.NoInternetConection) { ResultMessage = webEx.Message };
        }
        catch (Exception ex)
        {
            // cant find the full list of possible execptions in aws docs
            return new SignInContext(CognitoResult.Unknown) { ResultMessage = ex.Message };
        }
    }

`

from aws-sdk-net-extensions-cognito.

RidhwanDev avatar RidhwanDev commented on June 15, 2024 2

@philipogorman I think in your previous comment you've also figured out the design behind it however you're still using the DateTime.Now.AddHours(1) work around. This work around means you will always refresh the user's token. At the point in which you authenticate the user, you should store a property with a name like RefreshTokenExpirationTime and set this anywhere between an hour to 30 days from that moment you authenticate them. This RefreshTokenExpirationTime will dictate how long they have before their refresh token expires. I've always set mine to 25 days from the moment they are authenticated, which means if they keep logging in within 25 days they will always remained signed in -- they will be authenticated again and their refresh token will have a new expiration time. However if they login again 26 days since their last sign in then they will need to sign in again.

Using DateTime.Now.AddHours(1) will work because cognito will always try to refresh their user's token. It's essentially a force refresh. However it will not work in this situation: If the user has signed in and then leaves and doesn't come back to the app for over 30 days. (At this point the actual refresh token has expired, unless you have changed the expiration time of your refresh tokens) Your code of DateTime.Now.AddHours(1) will try to force refreshing the token again which will fail due to an expired refresh token. Your app may or may not handle this gracefully but it certainly isn't the behaviour you want.

@NGL321 I'm not sure if my comments have made sense, people don't seem to understand it. I don't think theres anything wrong with the code here per se but argument name is very misleading and there should be proper instructions on how to use it.

from aws-sdk-net-extensions-cognito.

TroySchmidt avatar TroySchmidt commented on June 15, 2024 2

This is still a "bug". I think the issue is that most people initiate the login and get the expiry for the access token. Then they try and use the same set of session tokens to refresh. The code is checking the expiry date and failing. The issue is that between authenticating and refreshing there are two different time frames, but only one is stored in the session tokens. So you have to provide your own new expiry time on the refresh that is valid so the SDK expiry validation passes. This usually isn't an issue since that is usually a month so knowing the exact time table for that is not needed. Also considering a new refresh token is given then that almost always works and doesn't require a login with password again.

from aws-sdk-net-extensions-cognito.

berniezhao11 avatar berniezhao11 commented on June 15, 2024 1

@jeffreythomasprice The trick was not really you adding expiration variable, it was the refresh token!

user.SessionTokens = new CognitoUserSession(
	user.SessionTokens.IdToken,
	user.SessionTokens.AccessToken,
	user.SessionTokens.RefreshToken,
	user.SessionTokens.IssuedTime,
	DateTime.Now.AddHours(1)
);

It was the user.SessionToken.RefreshToken you assigned to the session object that fixed your problem. The whole refresh token auth flow would not work if you don't even provide the refresh token.
Remember the InitiateRefreshTokenAuthRequest object only has AuthFlowType, nothing else.
I think it might be better to put RefreshToken into the InitiateRefreshTokenAuthRequest so we don't need to create a dummy session object just to hold the refresh token.

from aws-sdk-net-extensions-cognito.

sstevenkang avatar sstevenkang commented on June 15, 2024

If I understand the Cognito API correctly, you need a valid, non-expired token to be able to get a new token with a later expiry date. It looks like it's behaving as designed. Am I missing something here?

from aws-sdk-net-extensions-cognito.

jeffreythomasprice avatar jeffreythomasprice commented on June 15, 2024

My understanding is that the access token is what is important for the actual authentication component of any request, and is valid for 1 hour by default. The refresh token is what you can then use to request a new access token, and is valid for 30 days by default. I'm basing my understanding on this document: https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-with-identity-providers.html

Going by that, I should be able to use a particular access token for an hour, and then see a 401 when I try to continue using that (now expired) access token. At this point, I should still have the better part of 30 days to use the refresh token I got when I first authenticated to get a new access token. In my case I'm trying to set up an automated retry, where I see that 401, get a new access token, and retry the original request with the new access token.

This flow seems works fine when I apply the workaround where I mess with the expiration time variable so it passes the EnsureUserAuthenticated check and actually tries to do the refresh. For what it's worth, this exact same flow seems to be working fine in a web client using https://www.npmjs.com/package/amazon-cognito-identity-js.

from aws-sdk-net-extensions-cognito.

sstevenkang avatar sstevenkang commented on June 15, 2024

Hmmm. Thanks for the detailed write up. I'll take another look at this.

from aws-sdk-net-extensions-cognito.

prothschell-lowtcenter avatar prothschell-lowtcenter commented on June 15, 2024

Any luck with this bug?

from aws-sdk-net-extensions-cognito.

RidhwanDev avatar RidhwanDev commented on June 15, 2024

@berniezhao11 I don't think so. CreateRefreshTokenAuthRequest still calls EnsureUserAuthenticated which does this:

   if (SessionTokens == null || !SessionTokens.IsValid())
            {
                throw new NotAuthorizedException("User is not authenticated.");
            }

I think it might be better to put RefreshToken into the InitiateRefreshTokenAuthRequest so we don't need to create a dummy session object just to hold the refresh token.

If you don't create the session object, it won't pass this check. Also SessionTokens.IsValid will return false if it is past the expiration time, which doesn't make sense since you only need to refresh the token when it has expired?

I think EnsureUserAuthenticated should not be called in CreateRefreshTokenAuthRequest. Let me know your thoughts please.

@jeffreythomasprice Has commenting out/removing EnsureUserAuthenticated worked consistently for you?

from aws-sdk-net-extensions-cognito.

MosCD avatar MosCD commented on June 15, 2024

Is there any solution for this issue? it's 1 year old and I came across this error

from aws-sdk-net-extensions-cognito.

curtisshipley avatar curtisshipley commented on June 15, 2024

I am encountering this as well. If I try to refresh a valid token, it gives me a user not authenticated exception.

from aws-sdk-net-extensions-cognito.

curtisshipley avatar curtisshipley commented on June 15, 2024

It appears my issue had to do with enabling the remember device options on Cognito, but not supplying device info when refreshing.

from aws-sdk-net-extensions-cognito.

darbio avatar darbio commented on June 15, 2024

I am also struggling with this.

From my understanding, we should be able to pass a refresh token into the service and nothing else (we don't need a user id, access token, id token etc.). The refresh token should be authenticated and return new tokens.

This is how other ID providers work.

To make this work, I seem to need to have to pass in the sub of the user and then I can use the refresh key to get new tokens.

By googling, I found the following workaround:
https://stackoverflow.com/questions/54430978/unable-to-verify-secret-hash-for-client-at-refresh-token-auth

var userPool = new CognitoUserPool(this.settings.AWS.UserPoolId, this.settings.AWS.UserPoolClientId, this.client, this.settings.AWS.UserPoolClientSecret);

var user = userPool.GetUser("13d8e81c-538e-42e3-b46d-9d8dd84d32a6"); // this is the sub
user.SessionTokens = new CognitoUserSession(request.IdToken, string.Empty, request.RefreshToken, DateTime.UtcNow,
    DateTime.UtcNow.AddDays(1));

var authResponse = await user.StartWithRefreshTokenAuthAsync(new InitiateRefreshTokenAuthRequest()
{
    AuthFlowType = AuthFlowType.REFRESH_TOKEN
});

But it seems hacky...

from aws-sdk-net-extensions-cognito.

philipogorman avatar philipogorman commented on June 15, 2024

The DateTime.Now.AddHours(1) work around seems to work

from aws-sdk-net-extensions-cognito.

atiyka avatar atiyka commented on June 15, 2024

Hi all, I'm also struggling with this issue.
If I renew the tokens before the access token expires, it works fine, but as soon as the token expires I can't renew them - the StartWithRefreshTokenAuthAsync() throws an exception that the User is not authenticated.
I tried this workaround to set the expiration time to a future date (DateTime.Now.AddHours(1)). The same thing happens: if the access token isn't expired it works fine, but if it is, it throws an exception that: Refresh Token has been revoked.
Any suggestions?

from aws-sdk-net-extensions-cognito.

RidhwanDev avatar RidhwanDev commented on June 15, 2024

I've explained this before, the reason DateTime.Now.AddHours(1) or DateTime.UtcNow.AddDays(1) works is because it's the property ExpirationTime actually means RefreshTokenExpiration time. If you look at the code and how it is used, you will see that it is treated as a refresh token expiration. They have just not named it properly or made it clear enough that it is supposed to be that.

In my code I set this to 25 days from when the user first logs in. So if you logged in today, you have 25 more days to log in again and I will just refresh your token and give you a new one, and reset your 25 days. However if you log in after this 25 days then sorry mate your creds are expired and you need to log in again.

So everybody putting DateTime.Now.AddHours(1) in is just saying that I will always refresh your token because your refresh token is always valid until 1 hour in the future.

Does that make sense?

from aws-sdk-net-extensions-cognito.

atiyka avatar atiyka commented on June 15, 2024

Thanks for the answers!
I'm doing the same thing. So, when I login with user and password it gives me the access tokens, which expires within one hour. If I call that refresh function StartWithRefreshTokenAuthAsync within that one hour it gives me another tokens (except refresh token) which are valid for one hour from that point, and so on. It doesn't matter what I set as expiration.
But, if that specific one hour passes, without refreshing any tokens it doesn't gives me new tokens. So if try to call StartWithRefreshTokenAuthAsync() after more than one hour since the last login/refresh, it throws the exception what I already posted (Refresh Token has been revoked)...

Are you refreshing the tokens often, or is this scenario possible for you, to leave the app without communication with the server for more than one hour?

from aws-sdk-net-extensions-cognito.

philipogorman avatar philipogorman commented on June 15, 2024

there's a difference between the "access token" and the refresh token.
The access token must be refreshed every hour in my case - we set a timer in the app to do that. This is the token that is used in the api calls.

The refresh token, is the token used to refresh the access token. The "Refresh token expiration (days)" (Cognito->UserPool->General Settings->App clients->Show Details) is the amount of time since the last login that you can use the refresh token to get new tokens. After that period the refresh will fail.

It took a lot of fumbling around to get this working as desired!

from aws-sdk-net-extensions-cognito.

NGL321 avatar NGL321 commented on June 15, 2024

Im not sure who to ask, but @philipogorman and @RidhwanDev you seem to be up to date (Hamza no longer works on the SDK team). Is this a bug still being experienced?
If not, I want to leave a comment with official guidance and close it, but if it is I want to make sure it gets escalated ASAP.

😸 😷

from aws-sdk-net-extensions-cognito.

philipogorman avatar philipogorman commented on June 15, 2024

yes - we still have the workaround in our code, I haven't tested without the workaround though:

       `// The  "Refresh token expiration (days)" (Cognito->UserPool->General Settings->App clients->Show Details) is the
        // amount of time since the last login that you can use the refresh token to get new tokens.
        // After that period the refresh will fail
        // Using DateTime.Now.AddHours(1) is a workaround for https://github.com/aws/aws-sdk-net-extensions-cognito/issues/24
        user.SessionTokens = new CognitoUserSession(idToken, accessToken, refreshToken, issued, DateTime.Now.AddHours(1));

`

from aws-sdk-net-extensions-cognito.

philipogorman avatar philipogorman commented on June 15, 2024

@RidhwanDev your summary sounds correct to me

from aws-sdk-net-extensions-cognito.

ashishdhingra avatar ashishdhingra commented on June 15, 2024

Hi @jeffreythomasprice,

Please have a look at the comments made by @philipogorman and @RidhwanDev, and advise if the issue could be closed.

Thanks,
Ashish

from aws-sdk-net-extensions-cognito.

github-actions avatar github-actions commented on June 15, 2024

This issue has not recieved a response in 2 weeks. If you want to keep this issue open, please just leave a comment below and auto-close will be canceled.

from aws-sdk-net-extensions-cognito.

BatteryAcid avatar BatteryAcid commented on June 15, 2024

What’s the difference between the the ExpirationTime set in an CognitoUserSession object and the configuration set in the AWS Console under my User Pool app client’s “Refresh token expiration”?

Should I be matching the expiration time of what’s configured under the App client’s refresh token expiration to what I’m setting in CognitoUserSession? Or is this just to allow flexibility in how my app wants to handle the refresh?

I’m not sure how these two settings work together.

from aws-sdk-net-extensions-cognito.

davidsaldana avatar davidsaldana commented on June 15, 2024

In case anyone is still seeing this, the issuedTime and expirationTime parameters don't really matter for this call at all. I set these values to DateTime.MinValue and the code works just fine. See below:
cognitoUser.SessionTokens = new CognitoUserSession( credentials.IdTokenForRefresh, credentials.AccessTokenForRefresh, credentials.RefreshTokenForRefresh, // issuedTime and expiration time don't matter here // References: // https://github.com/aws/aws-sdk-net-extensions-cognito/issues/24 issuedTime: DateTime.MinValue, expirationTime: DateTime.MinValue);
I've tested with an expired refresh token and an unexpired refresh token (expired per aws user pool app client token expiration settings). In both cases, the call is attempted normally. However, they differ in that the call with the expired token returns a "Refresh Token has expired" response error and the call with the unexpired refresh token gets you a refreshed set of id and access tokens.

In my opinion what the aws cognito developers really should've done is simply provide an overloaded constructor like the following:
public CognitoUserSession(string idToken, string accessToken, string refreshToken) { IdToken = idToken; AccessToken = accessToken; RefreshToken = refreshToken; }
This would've prevented lots of confusion. Well that and better documentation. The aws sdk is certainly not the friendliest for developers.

from aws-sdk-net-extensions-cognito.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.