Modify request params with custom authentication

python, python-requests

Solution

Indeed, a `PreparedRequest` is now passed in, and the URL query string is already set from the parameters.

However, the `PreparedRequest.prepare_url()` method will let you update the URL with additional parameters:

class APIAuth(requests.auth.AuthBase):
    def __call__(self, request):
        api_secret = settings.API_SHARED_SECRET
        api_key = settings.API_KEY
        request.prepare_url(request.url, dict(
            api_key=api_key,
            timestamp=int(time.time()*1000)))
        signature = base64.b64encode(hmac.new(
            api_secret,
            msg=unquote(request.full_url),
            digestmod=hashlib.sha256
            ).digest()).decode()
        request.headers['Authorization'] = "signature {0}".format(signature)
        return request

Demo:

>>> import requests
>>> prepared = requests.Request(url='http://httpbin.org/get').prepare()
>>> prepared.url
'http://httpbin.org/get'
>>> prepared.prepare_url(prepared.url, {'foo': 'bar', 'spam': 42})
>>> prepared.url
'http://httpbin.org/get?foo=bar&spam=42'
>>> prepared.prepare_url(prepared.url, {'monty': 'python'})
>>> prepared.url
'http://httpbin.org/get?foo=bar&spam=42&monty=python'

By passing in `prepared.url` the URL is updated to add the extra parameters. New parameters are always additive; if a new parameter has the same name as an already added parameter the old parameter is not removed.

Problem

I've just upgraded my requests library to 2.3.0 (from 0.14.0), and my custom authentication is no longer working. The issue is that the custom authentication we use appends an API key and a timestamp to the request, so all of our helper methods don't need to do it. ``` class APIAuth(requests.auth.AuthBase): def __call__(self, request): api_secret = settings.API_SHARED_SECRET api_key = settings.API_KEY request.params.update(dict( api_key=api_key, timestamp=int(time.time()*1000))) signature = base64.b64encode(hmac.new( api_secret, msg=unquote(request.full_url), digestmod=hashlib.sha256 ).digest()).decode() request.headers['Authorization'] = "signature {0}".format(signature) return request ``` The error: ``` AttributeError: 'PreparedRequest' object has no attribute 'params' ``` Prepared request does not allow modification of the params dict, presumably because it has already been constructed. Is there a simple way to update the params dict from our custom authentication that leaves any existing params intact? Or do I have to bite the bullet and add these two parameters for every request method?

Original source