I have a short CURL script that I'm trying to convert to Python, but I'm having a decent amount of trouble doing so. I'm targeting an API that requires an auth string that is formatted <public_key>.<sha256 hmac of url and body>
.
My legacy setup is a simple PHP script that generates the hmac and runs a CURL command with the output. I'm trying to port this over to Python for a separate project.
Legacy code:
hmac.php
<?php
$public = 'PUBLIC_KEY';
$private = 'PRIVATE_KEY';
$url = $argv[1];
$body = $argv[2];
$hmac = hash_hmac('sha256', $url . $body, $private, true);
print($public . '.' . base64_encode($hmac));
Example command:
$ DATA='{"command": "say Just testing the API, ignore this..."}'
$ URL='https://website.url/api/user/<UUID>/command'
$ curl -X POST -d $DATA -H "Content-Type: application/json" -H "Authorization: Bearer $(php hmac.php $URL $DATA)" --url $URL
The Python Port
So far, I've figured out how to create the correct hmac digest for GET requests, but I'm having trouble with the POST requests I detailed above.
send_command.py:
def generate_bearer(pubkey, privkey, url, body):
h = hmac.new(privkey.encode('utf8'), (url + body).encode('utf8'), sha256)
encoded = b64encode(h.digest())
return pubkey + '.' + encoded.decode('utf-8')
def send_command(server, command):
target = '{}/server/{}/command'.format(url, server)
data = {'command': command}
bearer = generate_bearer(public, private, target, str(data))
headers = {'Authorization': 'Bearer {}'.format(bearer),
'content-type': 'application/json'}
r = requests.post(target, headers=headers, data=data)
if __name__ == '__main__':
print(send_command('<UUID>', 'say Just testing the API, ignore this...'))
As far as I can tell, I need to pass the full JSON string both to generate_bearer()
and as the data I'm POSTing in the request. However, with this current code, I get the error "The HMAC for the request was invalid." What am I doing wrong here?