Making an API call in Python with an API that requires a bearer token
Solution 1
It just means it expects that as a key in your header data
import requests
endpoint = ".../api/ip"
data = {"ip": "1.1.2.3"}
headers = {"Authorization": "Bearer MYREALLYLONGTOKENIGOT"}
print(requests.post(endpoint, data=data, headers=headers).json())
Solution 2
If you are using requests
module, an alternative option is to write an auth class, as discussed in "New Forms of Authentication":
import requests
class BearerAuth(requests.auth.AuthBase):
def __init__(self, token):
self.token = token
def __call__(self, r):
r.headers["authorization"] = "Bearer " + self.token
return r
and then can you send requests like this
response = requests.get('https://www.example.com/', auth=BearerAuth('3pVzwec1Gs1m'))
which allows you to use the same auth
argument just like basic auth, and may help you in certain situations.
Solution 3
The token has to be placed in an Authorization header according to the following format:
Authorization: Bearer [Token_Value]
Code below:
import urllib2
import json
def get_auth_token():
"""
get an auth token
"""
req=urllib2.Request("https://xforce-api.mybluemix.net/auth/anonymousToken")
response=urllib2.urlopen(req)
html=response.read()
json_obj=json.loads(html)
token_string=json_obj["token"].encode("ascii","ignore")
return token_string
def get_response_json_object(url, auth_token):
"""
returns json object with info
"""
auth_token=get_auth_token()
req=urllib2.Request(url, None, {"Authorization": "Bearer %s" %auth_token})
response=urllib2.urlopen(req)
html=response.read()
json_obj=json.loads(html)
return json_obj
Solution 4
Here is full example of implementation in cURL and in Python - for authorization and for making API calls
cURL
1. Authorization
You have received access data like this:
Username: johndoe
Password: zznAQOoWyj8uuAgq
Consumer Key: ggczWttBWlTjXCEtk3Yie_WJGEIa
Consumer Secret: uuzPjjJykiuuLfHkfgSdXLV98Ciga
Which you can call in cURL like this:
curl -k -d "grant_type=password&username=Username&password=Password" \
-H "Authorization: Basic Base64(consumer-key:consumer-secret)" \
https://somedomain.test.com/token
or for this case it would be:
curl -k -d "grant_type=password&username=johndoe&password=zznAQOoWyj8uuAgq" \
-H "Authorization: Basic zzRjettzNUJXbFRqWENuuGszWWllX1iiR0VJYTpRelBLZkp5a2l2V0xmSGtmZ1NkWExWzzhDaWdh" \
https://somedomain.test.com/token
Answer would be something like:
{
"access_token": "zz8d62zz-56zz-34zz-9zzf-azze1b8057f8",
"refresh_token": "zzazz4c3-zz2e-zz25-zz97-ezz6e219cbf6",
"scope": "default",
"token_type": "Bearer",
"expires_in": 3600
}
2. Calling API
Here is how you call some API that uses authentication from above. Limit
and offset
are just examples of 2 parameters that API could implement.
You need access_token
from above inserted after "Bearer "
.So here is how you call some API with authentication data from above:
curl -k -X GET "https://somedomain.test.com/api/Users/Year/2020/Workers?offset=1&limit=100" -H "accept: application/json" -H "Authorization: Bearer zz8d62zz-56zz-34zz-9zzf-azze1b8057f8"
Python
Same thing from above implemented in Python. I've put text in comments so code could be copy-pasted.
# Authorization data
import base64
import requests
username = 'johndoe'
password= 'zznAQOoWyj8uuAgq'
consumer_key = 'ggczWttBWlTjXCEtk3Yie_WJGEIa'
consumer_secret = 'uuzPjjJykiuuLfHkfgSdXLV98Ciga'
consumer_key_secret = consumer_key+":"+consumer_secret
consumer_key_secret_enc = base64.b64encode(consumer_key_secret.encode()).decode()
# Your decoded key will be something like:
#zzRjettzNUJXbFRqWENuuGszWWllX1iiR0VJYTpRelBLZkp5a2l2V0xmSGtmZ1NkWExWzzhDaWdh
headersAuth = {
'Authorization': 'Basic '+ str(consumer_key_secret_enc),
}
data = {
'grant_type': 'password',
'username': username,
'password': password
}
## Authentication request
response = requests.post('https://somedomain.test.com/token', headers=headersAuth, data=data, verify=True)
j = response.json()
# When you print that response you will get dictionary like this:
{
"access_token": "zz8d62zz-56zz-34zz-9zzf-azze1b8057f8",
"refresh_token": "zzazz4c3-zz2e-zz25-zz97-ezz6e219cbf6",
"scope": "default",
"token_type": "Bearer",
"expires_in": 3600
}
# You have to use `access_token` in API calls explained bellow.
# You can get `access_token` with j['access_token'].
# Using authentication to make API calls
## Define header for making API calls that will hold authentication data
headersAPI = {
'accept': 'application/json',
'Authorization': 'Bearer '+j['access_token'],
}
### Usage of parameters defined in your API
params = (
('offset', '0'),
('limit', '20'),
)
# Making sample API call with authentication and API parameters data
response = requests.get('https://somedomain.test.com/api/Users/Year/2020/Workers', headers=headersAPI, params=params, verify=True)
api_response = response.json()
Solution 5
import json
import os
import requests
def lambda_handler(event, context):
print(event)
item = list(map(lambda x: x['detail']['item'], event['inputData']))
print("item List :", item)
consumer_key = os.getenv('consumer_key')
consumer_secret = os.getenv('consumer_secret')
entitlement_url=os.getenv('entitlement_url')
storage_url=os.getenv('storage_url')
access_token = get_jwt_token(consumer_key,consumer_secret,entitlement_url)
print("Response from entitlement: ", access_token)
for listID in list:
print("listID: ", listID)
response = get_storage_service(access_token,storage_url,listID)
print("Response from storage: ", response.text)
return "Success"
def get_jwt_token(consumer_key, consumer_secret, url):
data = 'grant_type=client_credentials&client_id=' + consumer_key + '&client_secret=' + consumer_secret
header = {"Content-type": "application/x-www-form-urlencoded"}
try:
response = requests.post(url, data=data, headers=header)
access_token = json.loads(response.text)
final_response=access_token['access_token']
except requests.exceptions as err:
print(err)
final_response = 'error'
return final_response
def get_storage_service(jwt_token, url, list_id):
final_url = url + list_id + "/data"
print("Final url is :", final_url)
headers_api = {
'Authorization': 'Bearer ' + jwt_token
}
try:
response = requests.get(url=final_url, headers=headers_api)
except requests.exceptions as err:
print(err)
response = 'error'
return response
using enviornment variable
Related videos on Youtube
user4657
Updated on November 24, 2021Comments
-
user4657 over 2 years
Looking for some help with integrating a JSON API call into a Python program.
I am looking to integrate the following API into a Python .py program to allow it to be called and the response to be printed.
The API guidance states that a bearer token must be generated to allow calls to the API, which I have done successfully. However I am unsure of the syntax to include this token as bearer token authentication in Python API request.
I can successfully complete the above request using cURL with a token included. I have tried "urllib" and "requests" routes but to no avail.
Full API details: IBM X-Force Exchange API Documentation - IP Reputation
-
user4657 about 9 yearsThe above throws the following syntax error:
Traceback (most recent call last): File "bearerreturn.py", line 6, in <module> print requests.post(endpoint,data=data,headers=headers).json() TypeError: 'dict' object is not callable
Code Below:import requests endpoint = "https://xforce-api.mybluemix.net:443/api/ip" data = {"ip":"1.1.2.3"} headers = {"Bearer token":"TOKEN WAS INSERTED HERE"} print requests.post(endpoint,data=data,headers=headers).json()
Any Ideas? -
Joran Beasley about 9 yearsyou have an old version of requests ...
json
is a dict in your version and not a functionrequests.post(...).json
... dont call it -
user4657 about 9 yearsThanks Joran Beasley. Updated Requests library via pip and this allowed me to keep original syntax. However now when I run the above it outputs this .json response:
{u'error': u'Not authorized. Access is only allowed via https://exchange.xforce.ibmcloud.com/#/'}
This is same as if I hit the URL directly in a browser. Am I missing something with token or the way endpoint is configured? Code:import requests endpoint = "https://xforce-api.mybluemix.net:443/ipr/" data = {"ip":"1.1.2.3"} headers = {"Bearer token":"TOKEN_HERE"} print requests.post(endpoint,data=data,headers=headers).json()
-
Joran Beasley about 9 yearsunfortunately I cant really help with that... it is either a bad endpoint or your credentials are invalid (are you using their example token, that is only configured for their url?) or perhaps you need to put your app url in their deleoper panel for your code ... chances are thats your first token ... you need to exchange token for a refresh token that you can then use to get a more permanent token (at least thats how oauth2 usually works..)
-
Joran Beasley about 9 yearswhoops looks like i had the header wrong try the updated code
-
user4657 about 9 yearsI am using a uniquely generated token that was generated via their guide: xforce-api.mybluemix.net:443/auth/anonymousToken
-
Joran Beasley about 9 yearswell if i find myself with lots of free time ill give it a shot and see if i can get back to you ... can you give me a link to their guide?
-
user4657 about 9 yearsTried updated code: More success. Still throws following error though.
{u'error': u'Not found.'}
Code:import requests endpoint = "https://xforce-api.mybluemix.net:443/ipr/" data = {"ip":"8.8.8.8"} headers = {"Authorization":"Bearer REALLY_LONG_TOKEN_HERE"} print requests.post(endpoint,data=data,headers=headers).json()
API Documentation Here: xforce-api.mybluemix.net/doc/#!/Authentication/… Thanks for your help so far! It really is much appreciated Joran. -
SidJ over 4 yearsFor Python3 :
req = urllib.request.Request(urlstr, None, {"Authorization": "Bearer %s" % enc_authstr}) response = urllib.request.urlopen(req)
-
smido about 4 yearsThis might be useful with zeep too. It uses requests.auth type of authorizations (for http headers auth, not soap headers)
-
Sarang over 2 yearsThis works. However, I am facing a weird issue. First
requests
call always gives401
and second call (with same data) works! Is there a way to avoid the 2nd call? For now I am checking thestatus_code
of first call and if it's401
I am making a second call.