Invalid signature in request credentials Admin API

I am trying to get logs using admin API. I generated the HMAC signature using the python code from the Cisco documentation.

import base64, email.utils, hmac, hashlib, urllib

def sign(method, host, path, params, skey, ikey):
Return HTTP Basic Authentication (“Authorization” and “Date”) headers.
method, host, path: strings from request
params: dict of request parameters
skey: secret key
ikey: integration key

# create canonical string
now = email.utils.formatdate()
canon = [now, method.upper(), host.lower(), path]
args = []
for key in sorted(params.keys()):
    val = params[key].encode("utf-8")
        '%s=%s' % (urllib.parse.
                   quote(key, '~'), urllib.parse.quote(val, '~')))
canon = '\n'.join(canon)

# sign canonical string
sig =, encoding='utf-8'),
               bytes(canon, encoding='utf-8'),
auth = '%s:%s' % (ikey, sig.hexdigest())

# return headers
return {'Date': now, 'Authorization': 'Basic %s' % base64.b64encode(bytes(auth, encoding="utf-8")).decode()}

and tried to hit the endpoint using postman
URL = https://■■■■■■■■■■■■■■■■■■■■■■■■■■■■/admin/v1/logs/administrator
headers =
Authorization: Basic xxx
Date : Tue, 30 Aug 2022 10:17:16 -0000
Content-Type : application/x-www-form-urlencoded

Still I am getting 40103

“code”: 40103,
“message”: “Invalid signature in request credentials”,
“stat”: “FAIL”

Please let me know what I am missing here.


If you want to use Postman, another community member posted an example pre-request script to handle the authorization on the fly for each request here: Preauth API failing but check and ping are good - #11 by xrave. See if that helps you out.

If you actually just want to use Python to access Duo APIs, take a look at our Python API client at GitHub - duosecurity/duo_client_python: Python library for interacting with the Duo Auth, Admin, and Accounts APIs.

Hi Thanks!!

I tried with postman pre-request script, but still I get the same error.
“Invalid signature in request credentials”

Ah, well, you can’t hardcode the timestamp. Note the lines preceding the var timestamp line saying to uncomment them out to get the actual timestamp of the request.