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

NotAuthorizedException: SecretHash does not match for the client: xxxxxxxxxxxxxxxxxxx when trying refresh token flow #94

Closed
LoopIssuer opened this issue Oct 3, 2022 · 4 comments
Labels
closed-for-staleness guidance Question that needs advice or information. module/cognito-ext response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days.

Comments

@LoopIssuer
Copy link

Describe the bug

Hi,
I had an issue when trying to use RefreshToken flow. I get error:
NotAuthorizedException: SecretHash does not match for the client: xxxxxxxxxxxxxxxxxxx
I tried:
-using secret directly
-using GetSecretHash with userName, userEmail, USerID, User Sub Id
Always the same issue.

I'm trying:

 public async void GetCredsFromRefreshAsync_(string refreshToken, string accessToken, string idToken, string userName, string userId)
{
  var secretHash = GetSecretHash(userId + _cognitoCredentials.AppClientId);
            CognitoUserPool userPool = new CognitoUserPool(_cognitoCredentials.UserPoolId, _cognitoCredentials.AppClientId, _provider, _cognitoCredentials.Secret);
            CognitoUser user = new CognitoUser(userName, _cognitoCredentials.AppClientId, userPool, _provider, _cognitoCredentials.Secret);
            user.SessionTokens = new CognitoUserSession( null, null, refreshToken, DateTime.Now, DateTime.Now.AddHours(1));
            InitiateRefreshTokenAuthRequest refreshRequest = new InitiateRefreshTokenAuthRequest()
            {               
                AuthFlowType = AuthFlowType.REFRESH_TOKEN_AUTH
            };

            AuthFlowResponse authResponse = await user.StartWithRefreshTokenAuthAsync(refreshRequest).ConfigureAwait(false);`
}

        private string GetSecretHash(string value)
        {
            var key = _cognitoCredentials.Secret;
            using (var hmacsha256 = new HMACSHA256(Encoding.UTF8.GetBytes(key)))
            {
                var hash = hmacsha256.ComputeHash(Encoding.UTF8.GetBytes(value));
                return Convert.ToBase64String(hash);
            }
        }

Also tried with the same result:

       public async void GetCredsFromRefreshAsync(string refreshToken, string accessToken, string idToken, string userName, string userId)
        {
            var secretHash = GetSecretHash(userId + _cognitoCredentials.AppClientId);
            CognitoUserPool userPool = new CognitoUserPool(_cognitoCredentials.UserPoolId, _cognitoCredentials.AppClientId, _provider);
            CognitoUser user = new CognitoUser(userName, _cognitoCredentials.AppClientId, userPool, _provider);

            user.SessionTokens = new CognitoUserSession(idToken, accessToken, refreshToken, DateTime.Now, DateTime.Now.AddHours(1));

            var refreshReq = new InitiateAuthRequest();
            refreshReq.ClientId = _cognitoCredentials.AppClientId;

            refreshReq.AuthFlow = AuthFlowType.REFRESH_TOKEN_AUTH;
            refreshReq.AuthParameters.Add("SECRET_HASH", secretHash);
            refreshReq.AuthParameters.Add("REFRESH_TOKEN", refreshToken);


            var clientResp = await _provider.InitiateAuthAsync(refreshReq).ConfigureAwait(false);

            InitiateRefreshTokenAuthRequest refreshRequest = new InitiateRefreshTokenAuthRequest()
            {
                AuthFlowType = AuthFlowType.REFRESH_TOKEN_AUTH
            };
        }

Please help.

Expected Behavior

Get Refresh Token without error: NotAuthorizedException: SecretHash does not match for the client

Current Behavior

Cannot get Refresh Token, error occurs: NotAuthorizedException: SecretHash does not match for the client

Reproduction Steps

Use this code:

public async void GetCredsFromRefreshAsync_(string refreshToken, string accessToken, string idToken, string userName, string userId)
{
  var secretHash = GetSecretHash(userId + _cognitoCredentials.AppClientId);
            CognitoUserPool userPool = new CognitoUserPool(_cognitoCredentials.UserPoolId, _cognitoCredentials.AppClientId, _provider, _cognitoCredentials.Secret);
            CognitoUser user = new CognitoUser(userName, _cognitoCredentials.AppClientId, userPool, _provider, _cognitoCredentials.Secret);
            user.SessionTokens = new CognitoUserSession( null, null, refreshToken, DateTime.Now, DateTime.Now.AddHours(1));
            InitiateRefreshTokenAuthRequest refreshRequest = new InitiateRefreshTokenAuthRequest()
            {               
                AuthFlowType = AuthFlowType.REFRESH_TOKEN_AUTH
            };

            AuthFlowResponse authResponse = await user.StartWithRefreshTokenAuthAsync(refreshRequest).ConfigureAwait(false);`
}

        private string GetSecretHash(string value)
        {
            var key = _cognitoCredentials.Secret;
            using (var hmacsha256 = new HMACSHA256(Encoding.UTF8.GetBytes(key)))
            {
                var hash = hmacsha256.ComputeHash(Encoding.UTF8.GetBytes(value));
                return Convert.ToBase64String(hash);
            }
        }

Possible Solution

Please give me information, what is wrong with my code, or maybe there is some bug?

Additional Information/Context

No response

AWS .NET SDK and/or Package version used

Amazon.Extensions.CognitoAuthentication 2.2.1
Unity 2021.3.9f1

Targeted .NET Platform

.Net 4.x

Operating System and version

Windows 11

@LoopIssuer LoopIssuer added bug This issue is a bug. needs-triage This issue or PR still needs to be triaged. labels Oct 3, 2022
@ashishdhingra
Copy link
Contributor

Hi @TomaszWozniakMosina,

Good morning.

Please have a look at the code in comment #35 (comment) for guidance. The _cognitoCredentials.Secret in your code should be pointing to the value of secret configured in App Client.

(Just FYI, I do not see you using secretHash, so that might be redundant)

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 3, 2022
@LoopIssuer
Copy link
Author

Hi @ashishdhingra
Good morning.
Thanks for your reply.
However, when I use the code form #35 (comment) I still get error: SecretHash does not match for the client: xxxxxxxxxxxxxxxxxxx.

I tried use SecretHash computed and not computed with the below method - always get same error.

        private string GetSecretHash(string value)
        {
            var key = _cognitoCredentials.Secret;
            using (var hmacsha256 = new HMACSHA256(Encoding.UTF8.GetBytes(key)))
            {
                var hash = hmacsha256.ComputeHash(Encoding.UTF8.GetBytes(value));
                return Convert.ToBase64String(hash);
            }
        }

@ashishdhingra
Copy link
Contributor

ashishdhingra commented Oct 4, 2022

@TomaszWozniakMosina I'm unsure what you are doing wrong. The below customized code works properly (using Amazon.Extensions.CognitoAuthentication 2.2.3 on .NET Framework 4.8):

NOTE: The code below uses FallbackRegionFactory.GetRegionEndpoint() to determine region. You might want to set region value instead if the region is not configured in the default profile chain.

using Amazon;
using Amazon.CognitoIdentityProvider;
using Amazon.Extensions.CognitoAuthentication;
using Amazon.Runtime;
using System;
using System.IO;
using System.Text;
using System.Threading.Tasks;

namespace CognitoRefreshTokenTest
{
    internal class Program
    {
        private static string userPoolId;
        private static string clientId;
        private static string clientSecret;

        const int BufferSize = 10000;

        static void Main(string[] args)
        {
            Console.SetIn(new StreamReader(Console.OpenStandardInput(), Encoding.UTF8, false, BufferSize));

            Console.Write("Enter User Pool ID: ");
            userPoolId = Console.ReadLine();
            Console.Write("Enter Client ID: ");
            clientId = Console.ReadLine();
            Console.Write("Enter Client Secret: ");
            clientSecret = Console.ReadLine();

            bool reexecuteFlow = false;

            do
            {
                Console.Write("User Name: ");
                string userName = Console.ReadLine();

                while (string.IsNullOrWhiteSpace(userName))
                {
                    Console.Write("Please enter a valid User Name: ");
                    userName = Console.ReadLine();
                }

                Console.Write("Do you have a Refresh Token (Y/N): ");
                char hasRefreshTokenResponse = Convert.ToChar(Console.ReadLine());
                bool hasRefreshToken = (char.ToLower(hasRefreshTokenResponse) == 'y');
                Console.WriteLine();

                string passwordOrRefreshToken;

                if (!hasRefreshToken)
                {
                    Console.Write("Password: ");
                    passwordOrRefreshToken = Console.ReadLine();

                    while (string.IsNullOrWhiteSpace(passwordOrRefreshToken))
                    {
                        Console.Write("Please enter a valid Password: ");
                        passwordOrRefreshToken = Console.ReadLine();
                    }
                }
                else
                {
                    Console.Write("Existing Refresh Token: ");
                    passwordOrRefreshToken = Console.ReadLine();

                    while (string.IsNullOrWhiteSpace(passwordOrRefreshToken))
                    {
                        Console.Write("Please enter a valid Refresh Token: ");
                        passwordOrRefreshToken = Console.ReadLine();
                    }
                }

                Console.WriteLine("\nExecuting {0} auth flow.", (hasRefreshToken ? "Refresh Token" : "Username/Password"));
                AuthFlowResponse authFlowResponse = (hasRefreshToken ? GetCredsFromRefreshAsync(userName, passwordOrRefreshToken).GetAwaiter().GetResult() : GetCredentials(userName, passwordOrRefreshToken).GetAwaiter().GetResult());
                Console.WriteLine("ID Token: {0}\nAccess Token {1}\nRefresh Token: {2}", authFlowResponse.AuthenticationResult.IdToken, authFlowResponse.AuthenticationResult.AccessToken, authFlowResponse.AuthenticationResult.RefreshToken);

                Console.Write("\n\nRe-execute Flow (Y/N): ");
                char reexecuteFlowResponse = Convert.ToChar(Console.ReadLine());
                reexecuteFlow = (char.ToLower(reexecuteFlowResponse) == 'y');
            } while (reexecuteFlow);
        }

        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);
        }
    }
}

Output:

Enter User Pool ID: us-east-2_<<removed>>
Enter Client ID: 22<<removed>>
Enter Client Secret: gu8m<<removed>>
User Name: testuser
Do you have a Refresh Token (Y/N): n

Password: 14@Dec@1983
Executing Username/Password auth flow.
ID Token: eyJraWQiOiJ6cG9HODdOOHQ4XC9mMFp6cE<<removed>>
Access Token eyJraWQiOiI5Z0I4dzRUNFdrMWRMdThcL2U0<<removed>>
Refresh Token: eyJjdHkiOiJKV1QiLCJlbmMiOiJB<<removed>>


Re-execute Flow (Y/N):
y
User Name: testuser
Do you have a Refresh Token (Y/N): y

Existing Refresh Token: eyJjdHkiOiJKV1QiLCJlbmMiOiJB<<removed>>
Executing Refresh Token auth flow.
ID Token: eyJraWQiOiJ6cG9HODdOOHQ4XC9mMFp6cEJySVFXa<<removed>>
Access Token eyJraWQiOiI5Z0I4dzRUNFdrMWRMdThcL2U0THJsVGN<<removed>>
Refresh Token: eyJjdHkiOiJKV1QiLCJlbmMiOiJB<<removed>>


Re-execute Flow (Y/N):

You need to use the value of client secret configured in App Client from Cognito user pool console (refer below as an example):
Screen Shot 2022-10-04 at 10 37 00 AM

Thanks,
Ashish

@ashishdhingra ashishdhingra added guidance Question that needs advice or information. response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days. and removed bug This issue is a bug. response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days. labels Oct 4, 2022
@github-actions
Copy link

This issue has not received a response in 5 days. 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 closing-soon This issue will automatically close in 4 days unless further comments are made. closed-for-staleness and removed closing-soon This issue will automatically close in 4 days unless further comments are made. labels Oct 10, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
closed-for-staleness guidance Question that needs advice or information. 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

2 participants