-1

I have the need to POST a request to a service that requires a hash SHA256 signature for autentication. I have both "app_id" and "app_secret" used to generate the hash during the process.

I have tried to do it, but receiving an invalid signature from the service provider when trying to POST a request.

From the provider instructions, I need to:

1. Create a MAC string that will contain all request data. This should be the elements:

AppId + HTTP Method + URI + UNIX Timestamp + Nonce (unique string for each request) + base64 string from payload md5

2. Generate the SHA256 hash from the string in point 1, using the provided AppSecret. 3. The final authentication signature will be composed of the following elements:

[ApiKey AppId:hash:nonce:timestamp]

What I have done so far:

app_id = 'my_app_id'
app_secret = 'my_app_secret'
providerURL = 'https://the_provider_url'

#code for calling the POST method
def publish_data(number, date, status):
    endPointUrl = providerURL + "/v1/posting"
    
    #just for testing purposes
    number = '123456789'
    date = None #opcional
    status = 'valid'
    
    payload = "?number={}&date={}&status={}".format(str(number), str(date), str(status))
    strHash = hmac_generator(endPointUrl, 'POST', payload)
    request_headers = {'Authorization': "ApiKey " + strHash, 
                       'Content-Type': 'application/x-www-form-urlencoded'
                       }
    response = requests.post(endPointUrl, headers=request_headers)
    print('RESPONSE:', response.text)
#code for generating the hash
def hmac_generator(uri, method, body=None):
    timestamp = int(time.time())
    nonce = str(uuid.uuid4())

    content = ""
    if body is not None:
        body_md5 = hashlib.md5(body.encode('utf-8')).digest()
        content = base64.b64encode(body_md5).decode('utf-8')
    
    #Generate the based64 MAC 
    #AppId + HTTP Method + URI + UNIX Timestamp + Nonce + base64 string from payload md5
    
    message = app_id + method + uri + str(timestamp) + nonce + content
    message_bytes = message.encode('utf-8')
    
    #Generate the SHA256 hash
    signature = hmac.new(app_secret, msg=message_bytes, digestmod=hashlib.sha256).digest()
    hashed = base64.b64encode(signature).decode('utf-8')

    return "{}:{}:{}:{}".format(app_id, hashed, nonce, timestamp)

I believe it is something related to "payload" because when I try to use a GET method using the same approach, it is working fine.

Code below:

#This method does not use payload
def get_details(number):
    number = 'an existing number'
    strUrl = endPointUrl + "/getdetails/" + str(number)
    strHash = self.hmac_generator(strUrl, 'GET', None)
    request_headers = {
                    'Authorization': "ApiKey " + strHash, 
                    'Content-Type': 'application/x-www-form-urlencoded'
                       }
    response = requests.get(strUrl, headers=request_headers)
    return response

Any help? Thanks in advance

I have tried to create some code as per the original question. When trying to POST, I am getting an "invalid signature" error. When I try to GET, everything runs fine.

  • I'm not really sure but the `?` at the beginning of your payload seems weird. Maybe try removing that. – tobifasc Apr 18 '23 at 12:49
  • did you see: https://stackoverflow.com/questions/1306550/calculating-a-sha-hash-with-a-string-secret-key-in-python – JonSG Apr 18 '23 at 12:54
  • @tobifasc, thank you. Removed and problem remains the same. I still think is something related with the payload (content), because the GET methot works since it uses no payload... – Paulo Matos Apr 18 '23 at 13:10

1 Answers1

0

I found the problem.

I was lost sending the "payload" only in the "hmac_generator" method:

strHash = hmac_generator(endPointUrl, 'POST', payload)

...and forgot to include it in the requests:

Old code:

response = requests.post(endPointUrl, headers=request_headers)

Fixed code:

response = requests.post(strUrl, headers=request_headers, data=payload)

Problem was the payload not being sent to response.

Thank you