问题
Problem
"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
}
}
Boto3 code for REFRESH_TOKEN_AUTH
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.
Boto3 code for ADMIN_NO_SRP_AUTH
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**********].
Environment
Cognito User Pool with client secret enabled.
print boto.Version 2.49.0
Research
AWS Javascript JDK
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.
Related issues
- AWS Cognito Atomic Token Fails in Secret Hash
- Unable to verify secret hash for client in Amazon Cognito Userpools
References
- Cognito Admin Initiate Auth
- Boto3 admin_initiate_auth
- AWS Cognito User Pool Computing SecretHash Values
回答1:
Whether the behaviour is as expected or not is to be confirmed. For the moment, to work-around the problem.
From AWS
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 = "james@bond.com"
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 .
来源:https://stackoverflow.com/questions/54430978/unable-to-verify-secret-hash-for-client-at-refresh-token-auth