-
Notifications
You must be signed in to change notification settings - Fork 49
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
Issue using Refresh Token flow #75
Comments
Hi @BenWoodford, Good morning. Thanks for posting guidance question. Please refer the below working code sample that has capability to use RefreshToken. Kindly note that this is a sample (console) application and you might want to move the secrets to a configuration file. You should have the correct username that exists in CognitoUserPool to use the RefreshToken. Kindly note that this sample uses using System;
using System.Threading.Tasks;
using Amazon;
using Amazon.CognitoIdentityProvider;
using Amazon.Extensions.CognitoAuthentication;
using Amazon.Runtime;
namespace CognitoStartWithRefreshTokenAuthAsync
{
class Program
{
private static string userPoolId = "<<userpool_id>>";
private static string clientId = "<<client_id>>";
private static string clientSecret = "<<client_secret>>";
private static RegionEndpoint regionEndpoint = RegionEndpoint.USEast2; // Change the region appropriately. Credentials are loaded from default profile.
static void Main(string[] args)
{
Console.WriteLine("User Name: ");
string userName = Console.ReadLine();
while (string.IsNullOrWhiteSpace(userName))
{
Console.WriteLine("Please enter a valid User Name.");
userName = Console.ReadLine();
}
Console.WriteLine("Do you have a Refresh Token (Y/N): ");
char hasRefreshTokenResponse = Convert.ToChar(Console.Read());
bool hasRefreshToken = (char.ToLower(hasRefreshTokenResponse) == 'y');
Console.WriteLine();
Console.WriteLine("Password: ");
string password = Console.ReadLine();
while (string.IsNullOrWhiteSpace(password) && !hasRefreshToken)
{
Console.WriteLine("Please enter a valid Password.");
password = Console.ReadLine();
}
Console.WriteLine("Existing Refresh Token: ");
string refreshToken = Console.ReadLine();
while (string.IsNullOrWhiteSpace(refreshToken) && hasRefreshToken)
{
Console.WriteLine("Please enter a valid Refresh Token.");
refreshToken = Console.ReadLine();
}
AuthFlowResponse authFlowResponse = (!string.IsNullOrWhiteSpace(refreshToken) ? GetCredsFromRefreshAsync(userName, refreshToken).GetAwaiter().GetResult() : GetCredentials(userName, password).GetAwaiter().GetResult());
}
public static async Task<AuthFlowResponse> GetCredentials(string userName, string password)
{
var provider = new AmazonCognitoIdentityProviderClient(new AnonymousAWSCredentials(), FallbackRegionFactory.GetRegionEndpoint());
var userPool = new CognitoUserPool(userPoolId, clientId, provider, clientSecret);
var user = new CognitoUser(userName, clientId, userPool, provider, clientSecret);
AuthFlowResponse authResponse = await user.StartWithSrpAuthAsync(new InitiateSrpAuthRequest()
{
Password = password
}).ConfigureAwait(false);
while (authResponse.AuthenticationResult == null)
{
if (authResponse.ChallengeName == ChallengeNameType.NEW_PASSWORD_REQUIRED)
{
Console.WriteLine("Enter your desired new password: ");
string newPassword = Console.ReadLine();
authResponse = await user.RespondToNewPasswordRequiredAsync(new RespondToNewPasswordRequiredRequest()
{
SessionID = authResponse.SessionID,
NewPassword = newPassword
});
}
else if (authResponse.ChallengeName == ChallengeNameType.SMS_MFA)
{
Console.WriteLine("Enter the MFA Code sent to your device: ");
string mfaCode = Console.ReadLine();
authResponse = await user.RespondToSmsMfaAuthAsync(new RespondToSmsMfaRequest()
{
SessionID = authResponse.SessionID,
MfaCode = mfaCode
}).ConfigureAwait(false);
}
else
{
Console.WriteLine("Unrecognized authentication challenge.");
return null;
}
}
return authResponse;
}
public static async Task<AuthFlowResponse> GetCredsFromRefreshAsync(string userName, string refreshToken)
{
AmazonCognitoIdentityProviderClient provider = new AmazonCognitoIdentityProviderClient(new AnonymousAWSCredentials(), FallbackRegionFactory.GetRegionEndpoint());
CognitoUserPool userPool = new CognitoUserPool(userPoolId, clientId, provider, clientSecret);
CognitoUser user = new CognitoUser(userName, clientId, userPool, provider, clientSecret);
user.SessionTokens = new CognitoUserSession(null, null, refreshToken, DateTime.Now, DateTime.Now.AddHours(1));
InitiateRefreshTokenAuthRequest refreshRequest = new InitiateRefreshTokenAuthRequest()
{
AuthFlowType = AuthFlowType.REFRESH_TOKEN_AUTH
};
return await user.StartWithRefreshTokenAuthAsync(refreshRequest).ConfigureAwait(false);
}
}
} NOTE: In case you app client has client secret as well, you would need to pass them to This sample takes guidance from Amazon CognitoAuthentication Extension Library Examples. Hope this helps. Thanks, |
So just to confirm, there's no server-side settings I should be using, no requirement to use a client secret, etc? I just need a refresh token and a username. |
@BenWoodford You are not required to configure client secret for an app client. If you configured client secret for app client, then you need to would need to pass them to |
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. |
Keeping open until I have a chance to properly test (it also hasn’t been two weeks…?) |
Unfortunately I still get an To confirm, I'm getting the token from |
@BenWoodford In case you app client has client secret as well, you would need to pass them to |
There’s no client secret (presumably username/password login wouldn’t work in that case anyway?) |
@BenWoodford Thanks for your persistence. It appears that you are affected by the issue mentioned in #77 in public static async Task<AuthFlowResponse> GetCredsFromRefreshAsync(string userName, string refreshToken)
{
AmazonCognitoIdentityProviderClient provider = new AmazonCognitoIdentityProviderClient(new AnonymousAWSCredentials(), FallbackRegionFactory.GetRegionEndpoint());
CognitoUserPool userPool = new CognitoUserPool(userPoolId, clientId, provider, clientSecret);
CognitoUser user = new CognitoUser(userName, clientId, userPool, provider, clientSecret);
user.SessionTokens = new CognitoUserSession(null, null, refreshToken, DateTime.Now, DateTime.Now.AddHours(1).ToUniversalTime());
InitiateRefreshTokenAuthRequest refreshRequest = new InitiateRefreshTokenAuthRequest()
{
AuthFlowType = AuthFlowType.REFRESH_TOKEN_AUTH
};
return await user.StartWithRefreshTokenAuthAsync(refreshRequest).ConfigureAwait(false);
} There is another related issue #76 which states that refresh token auth flow should not check for expiration time of access token. Once the fix for #77 and #76 is implemented, I will update here accordingly. This is not longer a guidance issue and I will change the label to Thanks, |
@ashishdhingra thanks, I tried that out but still no avail unfortunately. Same "Invalid Refresh Token" error To confirm, Cognito's Client settings on the AWS Console shows "(no client secret)" - so presumably this means there is definitely not one set? To double-check, you don't need a client secret to use a refresh token do you? |
@BenWoodford No, you do not need client secret. To troubleshoot, could you please share screenshot of user pool and app client settings (with sensitive information masked). It works perfectly fine at my end. |
Will do tomorrow morning, thanks! Is there an email address I can send that to instead though? Just to avoid any information mishaps as it’s a client’s AWS account. |
@BenWoodford You can upload the screenshots here. However, please make sure that you mask out sensitive information. |
I've narrowed this down: if I disable device tracking I can use the refresh token, so the endpoint error isn't terribly helpful at all as the token itself is fine. However there's no documentation on how I ensure the device key is provided for the refresh flow, I've tried creating a device like the below using a remembered device key but it still returns an invalid refresh token:
As a side question, what is the appropriate way to handle refresh tokens and the user not being connected to the internet (in the case of a mobile app that isn't currently online)? Should I just assume that the refresh token is okay and let them use the app offline, or should I be tracking when I acquired the token? Given it doesn't seem to refresh when authenticating with a refresh token (or does using it extend the expiration?) I can't really go "Oh the expiration is up, I'll just log them out" as that would always be 30 days after the last user/pass auth |
Hi @BenWoodford, The refresh toke auth flow fix was implemented in Amazon.Extensions.CognitoAuthentication 2.2.2. Please verify if your scenario is working now in the latest version. Thanks, |
Will do if I get a chance, though I’ve since switched Hosted UI and talking to the OAuth2 refresh token endpoint directly which seems to be working without any problems thankfully. However while I’m here: how does one refresh a refresh token…? As otherwise after 30 days it’s just going to log the user out, but you don’t get new refresh tokens when doing refresh login |
@BenWoodford If the refresh token is expired, your app user must re-authenticate by signing in again to your user pool. You may find more details on Using the Refresh Token. There are multiple open issues related to device tracking #73, #28 and #10. Since the refresh token auth flow works for you with device tracking disabled and you have a workaround, I would close this issue as duplicate of these other issues. I would see how I can get these issues prioritized by development team. |
|
@ashishdhingra I'm running into this same issue and as I see that the original poster never confirmed that the issue was fixed. When device tracking is turned on, the user of a refresh token is failing. I don't see any documentation about what to do in this scenario if it does even work. |
Hi, I'm trying:
Also tried with the same result:
Please help. |
I'm using the snippet from this flow and can successfully retrieve an access token and refresh token from the
AuthenticationResult
value, but upon saving the refresh token and putting it back through the aforementioned snippet I getInvalid Refresh Token
as a response.Am I missing some key AWS-side config setting here or something like that? Is the client secret required for refresh keys maybe? (there isn't one set currently)
This is using the SDK 3.7.57.0 and Extensions 2.21 in Unity
The text was updated successfully, but these errors were encountered: