186

I am stuck at "Amazon Cognito Identity user pools" process.

I tried all possible codes for authenticating user in cognito userpools. But I always get error saying "Error: Unable to verify secret hash for client 4b*******fd".

Here is code:

AWS.config.region = 'us-east-1'; // Region
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
    IdentityPoolId: 'us-east-1:b64bb629-ec73-4569-91eb-0d950f854f4f'
});

AWSCognito.config.region = 'us-east-1';
AWSCognito.config.credentials = new AWS.CognitoIdentityCredentials({
    IdentityPoolId: 'us-east-1:b6b629-er73-9969-91eb-0dfffff445d'
});

AWSCognito.config.update({accessKeyId: 'AKIAJNYLRONAKTKBXGMWA', secretAccessKey: 'PITHVAS5/UBADLU/dHITesd7ilsBCm'})

var poolData = { 
    UserPoolId : 'us-east-1_l2arPB10',
    ClientId : '4bmsrr65ah3oas5d4sd54st11k'
};
var userPool = new AWSCognito.CognitoIdentityServiceProvider.CognitoUserPool(poolData);

var userData = {
     Username : 'ronakpatel@gmail.com',
     Pool : userPool
};

var cognitoUser = new AWSCognito.CognitoIdentityServiceProvider.CognitoUser(userData);

cognitoUser.confirmRegistration('123456', true,function(err, result) {
if (err) {
    alert(err);
    return;
}
console.log('call result: ' + result);
});
KyungHoon Kim
  • 2,859
  • 2
  • 23
  • 26
Ronak Patel
  • 3,324
  • 4
  • 21
  • 31
  • 16
    Accepted answer is NOT valid anymore. Instructions how to generate secret hash are here http://docs.aws.amazon.com/cognito/latest/developerguide/signing-up-users-in-your-app.html#cognito-user-pools-computing-secret-hash – jasiustasiu Nov 28 '17 at 11:00
  • Yes, and look at @Simon Buchan answer below for a JavaScript implementation. It works perfectly. – guzmonne Mar 13 '18 at 01:58
  • `Note that Generate client secret must be unchecked when creating a web app; the Amazon Cognito Identity SDK for JavaScript doesn’t support apps that have a client secret simply because the client secret could be easily viewed in your code.` https://aws.amazon.com/blogs/mobile/accessing-your-user-pools-using-the-amazon-cognito-identity-sdk-for-javascript/ – yadab Oct 23 '20 at 16:42

22 Answers22

229

It seems that currently AWS Cognito doesn't handle client secret perfectly. It will work in the near future but as for now it is still a beta version.

For me it is working fine for an app without a client secret but fails for an app with a client secret.

So in your user pool try to create a new app without generating a client secret. Then use that app to signup a new user or to confirm registration.

thomas.g
  • 3,894
  • 3
  • 29
  • 36
  • 1
    So can I work "app without a client secret" in javascript – Ronak Patel May 26 '16 at 09:08
  • 1
    as I said, create a new app inside your AWS UserPools console, and uncheck the "Generate client secret". Then in the code you've posted I think you can replace the ClientId in your poolData object with the client id corresponding to the app you've just created. – thomas.g May 26 '16 at 09:19
  • 1
    facing same problem in initiate auth with SRP_A . ClientError: An error occurred (NotAuthorizedException) when calling the InitiateAuth operation: Unable to verify secret hash for client ****** . How exactly this srp_a works ? i created srp_a using python srp module , now it says the above specified error . – Manuj Rastogi Oct 13 '16 at 10:50
  • 1
    @ManujRastogi you should open a new question for your specific problem – thomas.g Oct 13 '16 at 14:12
  • 17
    FYI: This just happened to me, just now. It's still working this way, Jan 2017. When I created an app with no client_secret, I was able to use the JS SDK. When I created an app with a client_secret, I got the same faillure as in the original question. – Cheeso Jan 06 '17 at 22:47
  • 6
    As of 21 Apr 2017, it still does not work using the AWS CLI when secret key was enabled for App Client. aws cognito-idp admin-initiate-auth \ --region ap-northeast-1 \ --user-pool-id MY_POOL_ID \ --client-id MY_CLIENT_ID \ --auth-flow ADMIN_NO_SRP_AUTH \ --auth-parameters USERNAME=username@gmail.com,PASSWORD=som3PassW0rd – Stanley Yong Apr 21 '17 at 13:51
  • 33
    As of Jan 2018, this is still not supported. The documentation on the Github repo https://github.com/aws/amazon-cognito-identity-js mentions it: `"When creating the App, the generate client secret box must be unchecked because the JavaScript SDK doesn't support apps that have a client secret."` – kakoma Jan 11 '18 at 11:27
  • 1
    Is it save to send this kind of data from the frontend without having client secret activated? – Linus Mar 18 '18 at 14:08
  • 1
    I'm getting the same error, but for AWS PowerShell. I get `Register-CGIPUserInPool : Unable to verify secret hash for client 6n*****` – J86 Apr 03 '18 at 14:06
  • 1
    As of Apr 2018 this still seems to hold true for Python SDK as well. Had to create an app without a secret. – Daniel Kvasnicka Apr 16 '18 at 07:27
  • 1
    See https://stackoverflow.com/a/50205454/1251137 to add the HashedSecret into calls for NodeJS – ptimson May 06 '18 at 23:45
  • 7
    May19 2018, same error we need to create app without client secret. – Dileep May 19 '18 at 14:59
  • 1
    July 12 2018, same error creating an app with client secret. – Nickadiemus Jul 12 '18 at 19:11
  • 4
    September 12 2018 -- Same issue. Even when not using a client that generates a secret, I get a 400 whether or not the user is authenticated. App functions as expected despite this, however. – foxtrotuniform6969 Sep 12 '18 at 15:29
  • 4
    March 2019, issue still happening. Creating a new user pool without a client secret fixed the issue. Thank you @thomas.g . – bsberry Mar 14 '19 at 02:35
  • 1
    Nov 19.Logbook entry - Day 1272 days after the comment. Issue still happening – David Bensoussan Nov 19 '19 at 11:02
  • 1
    As of Feb 2020, this is still not supported. – Sanyam Khurana Feb 18 '20 at 06:36
  • 2
    22 April 2020 it is still not working when secret key for client app is enabled. Without secret key is working – Keivan Apr 22 '20 at 21:20
  • 2
    Another reason to avoid Cognito like the plague, what an embarrassment of a product. – Eric Guan Jun 11 '20 at 03:22
  • 1
    Sep, 2020 , stumbled upon this , same issue. – Prateek Sep 02 '20 at 10:37
  • The same problem exists with the PHP SDK. Unclicking the "generate client secret" solves it – Enigma Plus Dec 11 '20 at 15:48
  • January 2021... Still the same, thanks a lot for solution! – E-Kami Jan 19 '21 at 14:01
  • March 2021: Workaround available for a client with both secret and id. Check my answer below. – Utkarsh Mar 26 '21 at 14:57
  • 1
    October 2021. Found a workaround: migrated to another identity provider – Dowwie Oct 26 '21 at 22:14
  • It's 2022, still facing the same issue :( – saintlyzero May 21 '22 at 01:38
  • It's Sep 2022, still same error. – amit pandya Sep 16 '22 at 07:22
88

According to the Docs: http://docs.aws.amazon.com/cognito/latest/developerguide/setting-up-the-javascript-sdk.html

The Javascript SDK doesn't support Apps with a Client Secret.

The instructions now state that you need to uncheck the "Generate Client Secret" when creating the app for the User Pool.

Dr Douglas GhD
  • 1,089
  • 8
  • 5
68

This might be a fews years late but just uncheck the "Generate client secret" option" and it will work for your web clients.

generate app client option

Tiisetso Tjabane
  • 2,088
  • 2
  • 19
  • 24
  • 12
    Note that you can't edit it after the client created , so create a new one if needed. – URL87 May 08 '19 at 08:28
  • If you create a new app client and you had an identity pool (on "Federated Identities") that uses a Cognito authentication provider, remember to update the app client id field with the id of the new app client. – AMS777 Jan 09 '20 at 10:32
  • Thanks @Tiisetso Tjabane – kartonnade Aug 13 '20 at 17:44
  • Just to clerify, you do not need to create a new User Pool. You need to create a new App Client under a User Pool. So if you already have a User Pool that contains users, you do not need to create an entire new user pool, just a new app client in that user pool. – jeninja Dec 13 '20 at 18:05
33

Since everyone else has posted their language, here's node (and it works in the browser with browserify-crypto, automatically used if you use webpack or browserify):

const crypto = require('crypto');

...

crypto.createHmac('SHA256', clientSecret)
  .update(username + clientId)
  .digest('base64')
Simon Buchan
  • 12,707
  • 2
  • 48
  • 55
30

I had the same problem in the .net SDK.

Here's how I solved in, in case anyone else needs it:

public static class CognitoHashCalculator
{
    public static string GetSecretHash(string username, string appClientId, string appSecretKey)
    {
        var dataString = username + appClientId;

        var data = Encoding.UTF8.GetBytes(dataString);
        var key = Encoding.UTF8.GetBytes(appSecretKey);

        return Convert.ToBase64String(HmacSHA256(data, key));
    }

    public static byte[] HmacSHA256(byte[] data, byte[] key)
    {
        using (var shaAlgorithm = new System.Security.Cryptography.HMACSHA256(key))
        {
            var result = shaAlgorithm.ComputeHash(data);
            return result;
        }
    }
}

Signing up then looks like this:

public class CognitoSignUpController
{
    private readonly IAmazonCognitoIdentityProvider _amazonCognitoIdentityProvider;

    public CognitoSignUpController(IAmazonCognitoIdentityProvider amazonCognitoIdentityProvider)
    {
        _amazonCognitoIdentityProvider = amazonCognitoIdentityProvider;
    }

    public async Task<bool> SignUpAsync(string userName, string password, string email)
    {
        try
        {
            var request = CreateSignUpRequest(userName, password, email);
            var authResp = await _amazonCognitoIdentityProvider.SignUpAsync(request);

            return true;
        }
        catch
        {
            return false;
        }
    }

    private static SignUpRequest CreateSignUpRequest(string userName, string password, string email)
    {
        var clientId = ConfigurationManager.AppSettings["ClientId"];
        var clientSecretId = ConfigurationManager.AppSettings["ClientSecretId"];

        var request = new SignUpRequest
        {
            ClientId = clientId,
            SecretHash = CognitoHashCalculator.GetSecretHash(userName, clientId, clientSecretId),
            Username = userName,
            Password = password,
        };

        request.UserAttributes.Add("email", email);
        return request;
    }
}
Ron Sijm
  • 8,490
  • 2
  • 31
  • 48
17

Amazon mention how Computing SecretHash Values for Amazon Cognito in their documentation with Java application code. Here this code works with boto 3 Python SDK.

app client details

You can find your App clients in left side menu under General settings. Get those App client id and App client secret to create SECRET_HASH. For your better understand I commented out all the outputs of each and every line.

import hashlib
import hmac
import base64

app_client_secret = 'u8f323eb3itbr3731014d25spqtv5r6pu01olpp5tm8ebicb8qa'
app_client_id = '396u9ekukfo77nhcfbmqnrec8p'
username = 'wasdkiller'

# convert str to bytes
key = bytes(app_client_secret, 'latin-1')  # b'u8f323eb3itbr3731014d25spqtv5r6pu01olpp5tm8ebicb8qa'
msg = bytes(username + app_client_id, 'latin-1')  # b'wasdkiller396u9ekukfo77nhcfbmqnrec8p'

new_digest = hmac.new(key, msg, hashlib.sha256).digest()  # b'P$#\xd6\xc1\xc0U\xce\xc1$\x17\xa1=\x18L\xc5\x1b\xa4\xc8\xea,\x92\xf5\xb9\xcdM\xe4\x084\xf5\x03~'
SECRET_HASH = base64.b64encode(new_digest).decode()  # UCQj1sHAVc7BJBehPRhMxRukyOoskvW5zU3kCDT1A34=

In the boto 3 documentation, we can see lot of time ask about SECRET_HASH. So above code lines help you to create this SECRET_HASH.

If you don't want to use SECRET_HASH just uncheck Generate client secret when creating an app.

new app create

Kushan Gunasekera
  • 7,268
  • 6
  • 44
  • 58
  • 1
    For me, this only worked if I switched msg = bytes(app_client_id + username, 'latin-1') to msg = bytes(username + app_client_id, 'latin-1'). To be clear, I switched the order of the clientId and the username such that the username appears first. – Joshua Wolff Jul 22 '19 at 21:01
  • 1
    Thanks a lot @JoshWolff, I mistakenly swap `app_client_id` and `username`. But I display the correct output as a comment which displays according to the `username` + `app_client_id`. Again and again thanks a lot. – Kushan Gunasekera Jul 23 '19 at 15:04
  • 1
    No problem at all! @Kushan Gunasekera – Joshua Wolff Jul 23 '19 at 23:55
15

For anybody interested in using AWS Lambda to sign up a user using the AWS JS SDK, these are the steps I did:

Create another lambda function in python to generate the key:

import hashlib
import hmac
import base64

secretKey = "key"
clientId = "clientid"
digest = hmac.new(secretKey,
                  msg=username + clientId,
                  digestmod=hashlib.sha256
                 ).digest()
signature = base64.b64encode(digest).decode()

Call the function through the nodeJS function in AWS. The signature acted as the secret hash for Cognito

Note: The answer is based heavily off George Campbell's answer in the following link: Calculating a SHA hash with a string + secret key in python

KyungHoon Kim
  • 2,859
  • 2
  • 23
  • 26
Molezz
  • 431
  • 1
  • 6
  • 7
13

Solution for golang. Seems like this should be added to the SDK.

import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/base64"
)

func SecretHash(username, clientID, clientSecret string) string {
    mac := hmac.New(sha256.New, []byte(clientSecret))
    mac.Write([]byte(username + ClientID))
    return base64.StdEncoding.EncodeToString(mac.Sum(nil))
}
syvex
  • 7,518
  • 9
  • 43
  • 47
11

Solution for NodeJS with SecretHash

It seems silly that AWS removed the secret key from the SDK as it will not be exposed in NodeJS.

I got it working in NodeJS by intercepting fetch and adding in the hashed key using @Simon Buchan's answer.

cognito.js

import { CognitoUserPool, CognitoUserAttribute, CognitoUser } from 'amazon-cognito-identity-js'
import crypto from 'crypto'
import * as fetchIntercept from './fetch-intercept'

const COGNITO_SECRET_HASH_API = [
  'AWSCognitoIdentityProviderService.ConfirmForgotPassword',
  'AWSCognitoIdentityProviderService.ConfirmSignUp',
  'AWSCognitoIdentityProviderService.ForgotPassword',
  'AWSCognitoIdentityProviderService.ResendConfirmationCode',
  'AWSCognitoIdentityProviderService.SignUp',
]

const CLIENT_ID = 'xxx'
const CLIENT_SECRET = 'xxx'
const USER_POOL_ID = 'xxx'

const hashSecret = (clientSecret, username, clientId) => crypto.createHmac('SHA256', clientSecret)
  .update(username + clientId)
  .digest('base64')

fetchIntercept.register({
  request(url, config) {
    const { headers } = config
    if (headers && COGNITO_SECRET_HASH_API.includes(headers['X-Amz-Target'])) {
      const body = JSON.parse(config.body)
      const { ClientId: clientId, Username: username } = body
      // eslint-disable-next-line no-param-reassign
      config.body = JSON.stringify({
        ...body,
        SecretHash: hashSecret(CLIENT_SECRET, username, clientId),
      })
    }
    return [url, config]
  },
})

const userPool = new CognitoUserPool({
  UserPoolId: USER_POOL_ID,
  ClientId: CLIENT_ID,
})

const register = ({ email, password, mobileNumber }) => {
  const dataEmail = { Name: 'email', Value: email }
  const dataPhoneNumber = { Name: 'phone_number', Value: mobileNumber }

  const attributeList = [
    new CognitoUserAttribute(dataEmail),
    new CognitoUserAttribute(dataPhoneNumber),
  ]

  return userPool.signUp(email, password, attributeList, null, (err, result) => {
    if (err) {
      console.log((err.message || JSON.stringify(err)))
      return
    }
    const cognitoUser = result.user
    console.log(`user name is ${cognitoUser.getUsername()}`)
  })
}

export {
  register,
}

fetch-inceptor.js (Forked and edited for NodeJS from Fork of https://github.com/werk85/fetch-intercept/blob/develop/src/index.js)

let interceptors = []

if (!global.fetch) {
  try {
    // eslint-disable-next-line global-require
    global.fetch = require('node-fetch')
  } catch (err) {
    throw Error('No fetch available. Unable to register fetch-intercept')
  }
}
global.fetch = (function (fetch) {
  return (...args) => interceptor(fetch, ...args)
}(global.fetch))

const interceptor = (fetch, ...args) => {
  const reversedInterceptors = interceptors.reduce((array, _interceptor) => [_interceptor].concat(array), [])
  let promise = Promise.resolve(args)

  // Register request interceptors
  reversedInterceptors.forEach(({ request, requestError }) => {
    if (request || requestError) {
      promise = promise.then(_args => request(..._args), requestError)
    }
  })

  // Register fetch call
  promise = promise.then(_args => fetch(..._args))

  // Register response interceptors
  reversedInterceptors.forEach(({ response, responseError }) => {
    if (response || responseError) {
      promise = promise.then(response, responseError)
    }
  })

  return promise
}

const register = (_interceptor) => {
  interceptors.push(_interceptor)
  return () => {
    const index = interceptors.indexOf(_interceptor)
    if (index >= 0) {
      interceptors.splice(index, 1)
    }
  }
}

const clear = () => {
  interceptors = []
}

export {
  register,
  clear,
}
ptimson
  • 5,533
  • 8
  • 35
  • 53
  • I was able to signup following your procedure, but I'm unable to sign in using this proc. Is there any modification that needs to be done to sign in? It will be very helpful if you could add it here. Thanks in Advance. – Vinay Wadagavi Jul 24 '20 at 03:51
  • @VinayWadagavi See [here](https://github.com/aws-amplify/amplify-js/issues/1368#issuecomment-854604617) for some commentary that may help your use case – wolfyuk Oct 27 '22 at 11:31
10

A quick fix for the above mentioned problem statement would be to delete the existing "App Client" and crate a new one with unchecked Generate client secret

Note : Don't forget to change the app client string in the code.

AWS Cognito

Abhishek Gautam
  • 1,617
  • 3
  • 18
  • 29
8

this is a sample php code that I use to generate the secret hash

<?php
    $userId = "aaa";
    $clientId = "bbb";
    $clientSecret = "ccc";
    $s = hash_hmac('sha256', $userId.$clientId, $clientSecret, true);
    echo base64_encode($s);
?>

in this case the result is:

DdSuILDJ2V84zfOChcn6TfgmlfnHsUYq0J6c01QV43I=
Titi Wangsa bin Damhore
  • 7,101
  • 4
  • 31
  • 36
  • Where Did you this hash – sumit sharma Sep 10 '20 at 14:28
  • If it's not apparent, the secret has to be provided under the 'AuthParameters' node of the request body with the key of 'SECRET_HASH' and not 'SecretHash' like other parameters. `'AuthParameters' => [ 'USERNAME' => $login, 'PASSWORD' => $password, 'SECRET_HASH' => $this->_createSecretHash($login), ],` – polygone Feb 11 '21 at 22:08
8

In Java you could use this code:

private String getSecretHash(String email, String appClientId, String appSecretKey) throws Exception {
    byte[] data = (email + appClientId).getBytes("UTF-8");
    byte[] key = appSecretKey.getBytes("UTF-8");

    return Base64.encodeAsString(HmacSHA256(data, key));
}

static byte[] HmacSHA256(byte[] data, byte[] key) throws Exception {
    String algorithm = "HmacSHA256";
    Mac mac = Mac.getInstance(algorithm);
    mac.init(new SecretKeySpec(key, algorithm));
    return mac.doFinal(data);
}
gandrademello
  • 111
  • 1
  • 6
  • Where do you utilize this secret hash in the SDK besides outputting it to the screen? – Aaron Feb 22 '17 at 23:55
  • 1
    Can anyone point to any AWS docs online where authenticating against the client secret is explained? The base64/sha256 signature-encodings are compelling solutions -- but worthless unless they are explicitly compliant with AWS docs spelling out how to authenticate against the client secret. – Kode Charlie Jun 20 '17 at 15:40
6

for JAVA and .NET you need to pass the secret has in the auth parameters with the name SECRET_HASH.

AdminInitiateAuthRequest request = new AdminInitiateAuthRequest
{
  ClientId = this.authorizationSettings.AppClientId,
  AuthFlow = AuthFlowType.ADMIN_NO_SRP_AUTH,
  AuthParameters = new Dictionary<string, string>
  {
    {"USERNAME", username},
    {"PASSWORD", password},
    {
      "SECRET_HASH", EncryptionHelper.GetSecretHash(username, AppClientId, AppClientSecret)
    }
  },
  UserPoolId = this.authorizationSettings.UserPoolId
};

And it should work.

DIF
  • 2,470
  • 6
  • 35
  • 49
4

The crypto package for javascript is deprecated so using crypto-js:

import CryptoJS from 'crypto-js';
import Base64 from 'crypto-js/enc-base64';

const secretHash = Base64.stringify(CryptoJS.HmacSHA256(username + clientId, clientSecret));

Remeber to run npm install @types/crypto-js crypto-js before

Santi Barbat
  • 2,097
  • 2
  • 21
  • 26
3

C++ with the Qt Framework

QByteArray MyObject::secretHash(
     const QByteArray& email,
     const QByteArray& appClientId, 
     const QByteArray& appSecretKey)
{
            QMessageAuthenticationCode code(QCryptographicHash::Sha256);
            code.setKey(appSecretKey);
            code.addData(email);
            code.addData(appClientId);
            return code.result().toBase64();
};
vpicaver
  • 1,771
  • 1
  • 15
  • 16
2

Here is my 1 command, and it works (Confirmed :))

EMAIL="EMAIL@HERE.com" \
CLIENT_ID="[CLIENT_ID]" \
CLIENT_SECRET="[CLIENT_ID]" \
&& SECRET_HASH=$(echo -n "${EMAIL}${CLIENT_ID}" | openssl dgst -sha256 -hmac "${CLIENT_SECRET}" | xxd -r -p | openssl base64) \
&& aws cognito-idp ...  --secret-hash "${SECRET_HASH}"
Tuong Le
  • 18,533
  • 11
  • 50
  • 44
  • 1
    That `openssl` bit caused some extraneous output for me, but this worked: `SECRET_HASH=$(echo -n "${EMAIL}${CLIENT_ID}" | openssl dgst -sha256 -binary -hmac "${CLIENT_SECRET}" | openssl base64)` – Aaron Dec 05 '20 at 20:17
2

This solution works in March 2021:

In case you're working with a client which has both "client_secret" and "client_id" generated, instead of calculating the SECRET_HASH and providing it to the function as specified in AWS docs, pass the "client_secret".

Note: I was trying to generate new tokens from the refresh token.

let result = await cognitoIdentityServiceProvidor
  .initiateAuth({
    AuthFlow: "REFRESH_TOKEN",
    ClientId: clientId,
    AuthParameters: {
      REFRESH_TOKEN: refresh_token,
      SECRET_HASH: clientSecret,
    },
  })
  .promise();

It's absurd, but it works!

Utkarsh
  • 502
  • 1
  • 5
  • 22
  • 2
    Could this be considered a security risk if **"Enable username password auth for admin APIs for authentication (ALLOW_ADMIN_USER_PASSWORD_AUTH)"** box is ticked on user pool app client configuration, and `initiateAuth` method is used from client facing code (e.g. React ) ? – Ian Sebastian Apr 09 '21 at 07:19
2

NodeJS solution:

  • Compute secret hash for authenticating action:

    import * as crypto from 'crypto';
    
    const secretHash = crypto
        .createHmac('SHA256', clientSecret)
        .update(email + clientId)
        .digest('base64');
    
  • Compute secret hash for refresh token action:

    import * as crypto from 'crypto';
    
    const secretHash = crypto
        .createHmac('SHA256', clientSecret)
        .update(sub + clientId)
        .digest('base64');
    

The parameter object looks like this:

  const authenticateParams = {
    ClientId: clientId,
    UserPoolId: poolId,
    AuthFlow: CognitoAuthFlow.ADMIN_NO_SRP_AUTH,
    AuthParameters: {
      PASSWORD: password,
      USERNAME: email,
      SECRET_HASH: secretHash,
    },
  };

  const refreshTokenParams = {
    ClientId: clientId,
    UserPoolId: poolId,
    AuthFlow: CognitoAuthFlow.REFRESH_TOKEN_AUTH,
    AuthParameters: {
      REFRESH_TOKEN: refreshToken,
      SECRET_HASH: secretHash,
    },
  };

Usage:

import * as CognitoIdentityProvider from 'aws-sdk/clients/cognitoidentityserviceprovider';

const provider = new CognitoIdentityProvider({ region });
provider.adminInitiateAuth(params).promise(); // authenticateParams or refreshTokenParams, return a promise object.
duykhoa
  • 2,227
  • 1
  • 25
  • 43
1

There might be a more compact version, but this works for Ruby, specifically in Ruby on Rails without having to require anything:

key = ENV['COGNITO_SECRET_HASH']
data = username + ENV['COGNITO_CLIENT_ID']
digest = OpenSSL::Digest.new('sha256')

hmac = Base64.strict_encode64(OpenSSL::HMAC.digest(digest, key, data))
Nikolay D
  • 329
  • 3
  • 11
0

Cognito Authentication

Error: App client is not configured for secret but secret hash was received

Providing secretKey as nil worked for me. Credentials provided include :-

  • CognitoIdentityUserPoolRegion (region)
  • CognitoIdentityUserPoolId (userPoolId)
  • CognitoIdentityUserPoolAppClientId (ClientId)
  • AWSCognitoUserPoolsSignInProviderKey (AccessKeyId)

    // setup service configuration
    let serviceConfiguration = AWSServiceConfiguration(region: CognitoIdentityUserPoolRegion, credentialsProvider: nil)
    
    // create pool configuration
    let poolConfiguration = AWSCognitoIdentityUserPoolConfiguration(clientId: CognitoIdentityUserPoolAppClientId,
                                                                    clientSecret: nil,
                                                                    poolId: CognitoIdentityUserPoolId)
    
    // initialize user pool client
    AWSCognitoIdentityUserPool.register(with: serviceConfiguration, userPoolConfiguration: poolConfiguration, forKey: AWSCognitoUserPoolsSignInProviderKey)
    

All above things work with below linked code sample.

AWS Sample code : https://github.com/awslabs/aws-sdk-ios-samples/tree/master/CognitoYourUserPools-Sample/Swift

Let me know if that doesn't work for you.

0

The below seems to work with .NET now, for asp.net pages using the Alexa Skills SDK for .NET by Time Heur

Inject dependency

        private readonly CognitoUserManager<CognitoUser> _userManager;
 public RegisterModel(
            UserManager<CognitoUser> userManager,
            )
 _userManager = userManager as CognitoUserManager<CognitoUser> as CognitoUserManager<CognitoUser>;

Then assign a hash

     var user = _pool.GetUser(Input.UserName);
_userManager.PasswordHasher.HashPassword(user,Input.Password);
 var result = await _userManager.CreateAsync(user, Input.Password);
0

I saw a .NET one suggested here, but here is the variation that worked for me since I couldn't find access to "EncryptionHelper.GetSecretHash":

private string GetHMAC(string text, string key)
{
    // TODO: null checks or whatever you want on your inputs...
    using (var hmacsha256 = new HMACSHA256(Encoding.UTF8.GetBytes(key)))
    {
        var hash = hmacsha256.ComputeHash(Encoding.UTF8.GetBytes(text));
        return Convert.ToBase64String(hash);
    }
}

And you call this for something like a sign up request as follows:

SignUpRequest signUpRequest = new SignUpRequest
{
    ClientId = "<your_client_app_id>",
    Password = "<the-password-your-user-wanted>",
    Username = "<the-username-your-user-wanted",
};

// TODO: add whatever else you need to on your sign up request (like email, phone number etc...)

// and the magic line right here:
signUpRequest.SecretHash = GetHMAC(
    signUpRequest.Username + "<your_client_app_id>",
    "<your_client_app_secret>");

SignUpResponse response = await _provider.SignUpAsync(signUpRequest);

For me this worked like a charm. I originally was putting the client app secret directly assigned to this "SecretHash" property, but from scanning the rest of the answers here, I realized I truly needed to hash some data using that key as an input to the hash.

cigien
  • 57,834
  • 11
  • 73
  • 112
Dev Leader
  • 312
  • 3
  • 9