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

Cognito StartWithRefreshTokenAuthAsync does not respect client secret #35

Closed
berniezhao11 opened this issue Apr 30, 2019 · 4 comments
Closed
Labels
bug This issue is a bug. closed-for-staleness module/cognito-ext response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days.

Comments

@berniezhao11
Copy link

berniezhao11 commented Apr 30, 2019

Problem

When using refresh token to authenticate against a client that has clientSecret, it throws exception Unable to verify secret hash for client

Sample code

var userPool = new CognitoUserPool(_cognitoOptions.UserPoolId, _cognitoOptions.ClientId, _cognitoClient, _cognitoOptions.ClientSecret);
            var user = new CognitoUser(credentials.UserName, _cognitoOptions.ClientId, userPool, _cognitoClient, _cognitoOptions.ClientSecret);

            // need to manually create a SessionTokens object and add refresh token in
            user.SessionTokens = new CognitoUserSession(null, null, credentials.RefreshToken, DateTime.UtcNow, DateTime.UtcNow.AddHours(1));

            var refreshRequest = new InitiateRefreshTokenAuthRequest()
            {
                AuthFlowType = AuthFlowType.REFRESH_TOKEN_AUTH
            };
            var response = await 
            user.StartWithRefreshTokenAuthAsync(refreshRequest).ConfigureAwait(false);
...

Analysis

When authenticating using password, the SecretHash property is generated and will be used in further validation.

private RespondToAuthChallengeRequest CreateSrpPasswordVerifierAuthRequest(InitiateAuthResponse challenge,
                                                                                   string password,
                                                                                   Tuple<BigInteger, BigInteger> tupleAa)
        {
...
            if (!string.IsNullOrEmpty(ClientSecret))
            {
                SecretHash = CognitoAuthHelper.GetUserPoolSecretHash(Username, ClientID, ClientSecret);
                srpAuthResponses.Add(CognitoConstants.ChlgParamSecretHash, SecretHash);
            }
...

However when authenticating using refresh token, the SecretHash is never created.

private InitiateAuthRequest CreateRefreshTokenAuthRequest(AuthFlowType authFlowType)
        {
...
            if (!string.IsNullOrEmpty(SecretHash))
            {
                initiateAuthRequest.AuthParameters.Add(CognitoConstants.ChlgParamSecretHash, SecretHash);
            }
...
@assyadh assyadh self-assigned this May 8, 2019
@Gidmark
Copy link

Gidmark commented Nov 12, 2019

Any status update for this?

@Coldplayer1995
Copy link

Any update ?

@ashishdhingra ashishdhingra added bug This issue is a bug. module/cognito-ext needs-triage This issue or PR still needs to be triaged. labels Aug 7, 2020
@ashishdhingra
Copy link
Contributor

ashishdhingra commented Oct 19, 2020

Hi @berniezhao11,

Good afternoon.

I tried to reproduce the issue. However, it is not reproducible using the following code:

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 = "<User Pool ID>";
        private static string clientId = "<App Client ID>";
        private static string clientSecret = "<App 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);
        }
    }
}

.csproj file

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.1</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="AWSSDK.Extensions.CognitoAuthentication" Version="0.9.4" />
  </ItemGroup>
</Project>

STEPS

  1. Execute the above code, specifying N for "Do you have a Refresh Token (Y/N): " prompt. Before returning from GetCredentials(), take note of RefreshToken under user object.
  2. Now re-execute the above code, this time specifying Y for "Do you have a Refresh Token (Y/N): " prompt and then specifying the refresh token noted in step 1 above for "Existing Refresh Token: " prompt.

The refresh token flow works properly, where secret is configured for app client.

(I do see that the RefreshToken in user object after executing user.StartWithRefreshTokenAuthAsync() gets reset to null. We already have another issue #22 for the same)

Please confirm if this is still an issue with the latest version of AWSSDK.Extensions.CognitoAuthentication (version 0.9.4 used in above example) or if this issue could be closed.

Thanks,
Ashish

@ashishdhingra ashishdhingra added response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days. and removed needs-triage This issue or PR still needs to be triaged. labels Oct 19, 2020
@github-actions
Copy link

github-actions bot commented Nov 3, 2020

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.

@github-actions github-actions bot added the closing-soon This issue will automatically close in 4 days unless further comments are made. label Nov 3, 2020
@github-actions github-actions bot added closed-for-staleness and removed closing-soon This issue will automatically close in 4 days unless further comments are made. labels Nov 10, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug This issue is a bug. closed-for-staleness module/cognito-ext response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days.
Projects
None yet
Development

No branches or pull requests

6 participants