"Unable to verify secret hash for client ..." at REFRESH_TOKEN_AUTH auth flow.
{
"Error": {
"Code": "NotAuthorizedException",
"Message": "Unable to verify secret hash for client 3tjdt39cq4lodrn60kjmsb****"
},
"ResponseMetadata": {
"HTTPHeaders": {
"connection": "keep-alive",
"content-length": "114",
"content-type": "application/x-amz-json-1.1",
"date": "Tue, 29 Jan 2019 22:22:35 GMT",
"x-amzn-errormessage": "Unable to verify secret hash for client 3tjdt39cq4lodrn60kjmsbv3jq",
"x-amzn-errortype": "NotAuthorizedException:",
"x-amzn-requestid": "610368ec-2414-11e9-9671-f11a8cac1e43"
},
"HTTPStatusCode": 400,
"RequestId": "610368ec-2414-11e9-9671-f11a8cac1e43",
"RetryAttempts": 0
}
}
Followed the AWS documentation (as in the references below).
For REFRESH_TOKEN_AUTH/REFRESH_TOKEN: REFRESH_TOKEN (required), SECRET_HASH (required if the app client is configured with a client secret), DEVICE_KEY
response = get_client().admin_initiate_auth(
UserPoolId=USER_POOL_ID,
ClientId=CLIENT_ID,
AuthFlow='REFRESH_TOKEN_AUTH',
AuthParameters={
'REFRESH_TOKEN': refresh_token,
'SECRET_HASH': get_secret_hash(username)
}
)
It does not happen at ADMIN_NO_SRP_AUTH auth flow with the same secret hash value.
response = get_client().admin_initiate_auth(
UserPoolId=USER_POOL_ID,
ClientId=CLIENT_ID,
AuthFlow='ADMIN_NO_SRP_AUTH',
AuthParameters={
'USERNAME': username,
'SECRET_HASH': get_secret_hash(username),
'PASSWORD': password
},
ClientMetadata={
'username': username,
'password': password
}
)
The same secret hash works with 200.
{
"AuthenticationResult": {
"AccessToken": ...,
"TokenType": "Bearer"
},
"ChallengeParameters": {},
"ResponseMetadata": {
"HTTPHeaders": {
"connection": "keep-alive",
"content-length": "3865",
"content-type": "application/x-amz-json-1.1",
"date": "Tue, 29 Jan 2019 22:25:33 GMT",
"x-amzn-requestid": "cadf53cf-2414-11e9-bba9-4b60b3285418"
},
"HTTPStatusCode": 200,
"RequestId": "cadf53cf-2414-11e9-bba9-4b60b3285418",
"RetryAttempts": 0
}
}
Both uses the same logic to generate the secret hash.
def get_secret_hash(username):
msg = username + CLIENT_ID
digest = hmac.new(
str(CLIENT_SECRET).encode('utf-8'),
msg = str(msg).encode('utf-8'),
digestmod=hashlib.sha256
).digest()
hash = base64.b64encode(digest).decode()
log_debug("secret hash for cognito UP is [{0}]".format(hash))
return hash
The value is the same:
secret hash for cognito UP is [6kvmKb8almXpYKvfEbE9q4r1Iq/SuQvP8H**********].
Cognito User Pool with client secret enabled.
print boto.Version 2.49.0
AWS Amplify Javascript JDK does not support client secret as stated in Github but no report found so far on Boto3.
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.
Whether the behaviour is as expected or not is to be confirmed. For the moment, to work-around the problem.
The cause and work-around identified by an AWS guy.
when you have an “@” in the username you get that error on the REFRESH_TOKEN_AUTH call. Cognito generates a UUID-style username for them. And you have to use that during the refresh call.
Sample code provided to refresh the tokens.
import boto3
import hmac
import hashlib
import base64
import time
import jwt
Region = "us-east-1"
UserPoolId = "Your userpool ID"
AppClientId = "yyyy"
AppClientSecret = "zzzz"
Username = "[email protected]"
Password = "shakennotstirred"
Signature = hmac.new(AppClientSecret, Username+AppClientId,digestmod=hashlib.sha256)
Hash = base64.b64encode(Signature.digest())
Cognito = boto3.client("cognito-idp", region_name=Region)
AuthResponse = Cognito.admin_initiate_auth(
AuthFlow="ADMIN_NO_SRP_AUTH",
ClientId=AppClientId,
UserPoolId=UserPoolId,
AuthParameters={"USERNAME":Username, "PASSWORD":Password, "SECRET_HASH":Hash})
IdToken = AuthResponse["AuthenticationResult"]["IdToken"]
RefreshToken = AuthResponse["AuthenticationResult"]["RefreshToken"]
Decoded = jwt.decode(IdToken, verify=False)
DecodedUsername = Decoded["cognito:username"]
NewSignature = hmac.new(AppClientSecret, DecodedUsername+AppClientId, digestmod=hashlib.sha256) #!! Generate new signature and hash
NewHash = base64.b64encode(NewSignature.digest())
RefreshResponse = Cognito.admin_initiate_auth(
AuthFlow="REFRESH_TOKEN_AUTH",
ClientId=AppClientId,
UserPoolId=UserPoolId,
AuthParameters={"REFRESH_TOKEN":RefreshToken, "SECRET_HASH":NewHash}) #!! Use the new hash
NewIdToken = RefreshResponse["AuthenticationResult"]["IdToken"]
print("NewIdToken: "+NewIdToken)
The example uses Python2. To install the packages required.
pip2 install cryptography -t .
pip2 install PyJWT -t .
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With