Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to verify secret hash for client at REFRESH_TOKEN_AUTH

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
like image 603
mon Avatar asked Jan 29 '19 23:01

mon


1 Answers

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 = "[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 .
like image 157
mon Avatar answered Sep 20 '22 13:09

mon