Comments (31)
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.
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.
@ assyadh
Awesome!!!
I took like more than a year !!!!
Finger crossed for 2021
from aws-sdk-net-extensions-cognito.
@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.
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.
Hi everyone,
I'll have a look at this shortly and will narrow down the issue.
H
from aws-sdk-net-extensions-cognito.
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.
@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.
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.
@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.
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.
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.
Hmmm. Thanks for the detailed write up. I'll take another look at this.
from aws-sdk-net-extensions-cognito.
Any luck with this bug?
from aws-sdk-net-extensions-cognito.
@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 theInitiateRefreshTokenAuthRequest
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.
Is there any solution for this issue? it's 1 year old and I came across this error
from aws-sdk-net-extensions-cognito.
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.
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.
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.
The DateTime.Now.AddHours(1)
work around seems to work
from aws-sdk-net-extensions-cognito.
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.
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.
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.
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.
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.
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.
@RidhwanDev your summary sounds correct to me
from aws-sdk-net-extensions-cognito.
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.
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.
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.
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)
- There doesn't appear to be an ability to use UserContextData HOT 2
- CognitoUser.ListDevicesAsync() doesn't support returning pagination token. HOT 4
- `CognitoAuthHelper.GetAssemblyFileVersion` Expensive CPU Wise HOT 5
- Async methods should ALWAYS accept an optional cancellation token HOT 4
- Tag NuGet release commits HOT 2
- Include pdb and xml in NuGet package HOT 2
- Version 2.4.1 throws MissingMethodException when used with SignInManager HOT 4
- Refresh Token error - SecretHash does not match for the client HOT 9
- StartWithSrpAuthAsync Not Sync Safe HOT 9
- Verification codes other than the first one are not working HOT 4
- Unable to re-authenticate (not refresh) using the same device key HOT 7
- Avoid checking _access_ token expiry when trying to refresh access via a refresh token. HOT 7
- Recent change to use DateTime.UtcNow was a breaking change (at least for our application) HOT 11
- Custom Authentication Flow with SRP Password Verification HOT 7
- Extensions CognitoAuthentication Documentation HOT 4
- A deadlock occurs with Android and C# when trying to create a provider with Amazon.CognitoIdentityProvider.AmazonCognitoIdentityProviderClient HOT 5
- Invalid Refresh Token when using Refresh Token with Device Tracking HOT 7
- NotAuthorizedException: SecretHash does not match for the client: xxxxxxxxxxxxxxxxxxx when trying refresh token flow HOT 4
- Missing Authentication Token when trying to use ListUsersRequest HOT 2
- UserNotConfirmedException - how to resend confirmation code for not completed signup in .NET HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from aws-sdk-net-extensions-cognito.