Search code examples
pythonauthorizationnest-api

Why does Bearer not work in requests authorization header?


I'm having a problem sending an authorization token with Bearer to NEST API via python requests:

curl https://developer-api.nest.com -H "Authorization: Bearer c.123"
-H "Content-Type: application/json"

works fine, however:

nest_url = "https://developer-api.nest.com"
headers = {'Authorization': str('Bearer ' + token), 'Content-type': 'application/json'}
print(headers)
nest_data_req = requests.get(nest_url, headers=headers)

which prints as:

{'Content-type': 'application/json', 'Authorization': 'Bearer c.123'}

fails with a 401 unauthorized, as far as I can tell they are trying to make the same request so why does curl work (and postman for that matter) and python requests fail?

The following image shows the same working in postman:

enter image description here Update:

So this code works 1 in 10 times (the other 9+ give me 401 unauthorized):

 url = "https://developer-api.nest.com/"
    auth_t = token.encode("ascii", "ignore")
    headers = {
        'authorization': "Bearer " + auth_t,
        'content-type': "application/json",
        'cache-control': "no-cache",
    }
    response = requests.request("GET", url, headers=headers)
    print(response.text)

if I press submit in postman it works everytime without fail.


Solution

  • Turns this is a result of nest's API redirecting so you could consider this either a bug - as headers are removed from the redirected request, and headers should be on the session. Or a 'feature' as they were trying to resolve a CVE.

    So here is a prototyped way to handle this:

    def get_nest_data(token):
        url = "https://developer-api.nest.com/"
        auth_t = token.encode("ascii", "ignore")
        headers = {
            'authorization': "Bearer " + auth_t,
            'content-type': "application/json",
        }
    
        try:
            init_res = requests.get('https://developer-api.nest.com', headers=headers, allow_redirects=False)
            if init_res.status_code == 307:
                api_response = requests.get(init_res.headers['Location'], headers=headers, allow_redirects=False)
                if  api_response.status_code == 200:
                    return api_response.json()
            elif init_res.status_code == 200:
                return init_res.json()
        except Exception as ce:
            print(ce)