Bird_Muffin
Bird_Muffin

Reputation: 19

Authenticating API Request outside of Postman using Python

I am using an API for a portfolio management software and have been provided some documentation on how to implement it through Postman. The results come clean through Postman, but when I try to replicate the script through Python, I am unable to authenticate. I am not well versed in any other language besides Python and I am no API expert (especially when it comes to authentication). I was hoping that someone might be able to look through this code and see if anything seems incorrect with respect to creating a unique signature. Or, if anyone has had experience with creating an HMAC signature using the python requests structure.

import requests
import uuid
import time
import hmac
import base64
import hashlib
import math

url = "url"

payload = "{\n\t\"firm\": \"XXXXXXXX\",\n\t\"id\": \"#######\",\n\t\"data\": {\n\t\t\"tracking_preference\": 2\n\t} \n}\n"

apikey = 'apikey'

uuid = str(uuid.uuid4())
ts = math.floor(time.time())
timestamp = str(ts)

signature = timestamp+uuid

#signature_bytes = signature.encode('UTF8')
#secret_bytes = base64.standard_b64decode(apikey)

signature_bytes = bytes(signature, 'UTF8')
secret_bytes = bytes(apikey, 'UTF8')

signature_hash = hmac.new(secret_bytes, signature_bytes, hashlib.sha256).digest()
hmac = base64.b64encode(signature_hash).decode()


headers = {
    'X-SL-UUID': uuid,
    'X-SL-Timestamp': timestamp,
    'X-SL-HMAC': hmac,
    'Content-Type': "application/json",
    'User-Agent': "PostmanRuntime/7.18.0",
    'Accept': "*/*",
    'Cache-Control': "no-cache",
    'Postman-Token': "unique token",
    'Host': "xxxxxx-xxx.smartleaf.com",
    'Accept-Encoding': "gzip, deflate",
    'Content-Length': "89",
    'Connection': "keep-alive",
    'cache-control': "no-cache"
    }

response = requests.request("POST", url, data=payload, headers=headers)

print(response.text)

Anything with "XXX" or "###" is information I have blurred out. Thanks in advance!

Here is the pre-request script on Postman using JS:

var apikey = '##########';

var uuidlib = require('uuid');
var uuid = uuidlib.v4();

var timestamp = Math.floor(Date.now() / 1000).toString();

var hash = CryptoJS.HmacSHA256(timestamp.concat(uuid), apikey);

postman.setEnvironmentVariable('timestamp', timestamp);
postman.setEnvironmentVariable('uuid', uuid);
postman.setEnvironmentVariable('hmac', hash);

Upvotes: 0

Views: 1306

Answers (1)

Sam Mason
Sam Mason

Reputation: 16214

directly translating that Javascript code results in:

import hmac
import hashlib
import time
import uuid
import requests

apikey = b'##########'
url = 'https://xxxxxx-xxx.smartleaf.com/'
payload = {'firm': 'XXXXXXXX', 'id': '#######', 'data': {'tracking_preference': 2}}

reqid = str(uuid.uuid4())
reqts = str(int(time.time()))

key = hmac.new(apikey, f'{reqts}{reqid}'.encode('ascii'), hashlib.sha256).hexdigest()

headers = {
    'X-SL-UUID': reqid,
    'X-SL-Timestamp': reqts,
    'X-SL-HMAC': key,
}

response = requests.post(url, json=payload, headers=headers)

the main this is you were encoding the digest in base64 rather than hexadecimal

obviously I can't test this, but hopefully it's about right

Upvotes: 1

Related Questions