There are lot of questions posted how to consume the REST services with python, but none of them worked for me,
currently with the below curl cli i can get the authentication token.
curl cli
curl -v --user username:pass1234 -H "content-type: application/json" -X POST -d "" https://mywebsite/api/v1/auth/token-services --insecure
when i execute the above cli i get the json response as below :
output snip from above curl cli
< HTTP/1.1 200 OK
< Server: nginx/1.4.2
< Date: Mon, 14 Apr 2014 23:22:41 GMT
< Content-Type: application/json
< Content-Length: 201
< Connection: keep-alive
Connection #0 to host <ipaddress> left intact
* Closing connection #0
* SSLv3, TLS alert, Client hello (1):
{"kind": "object#auth-token", "expiry-time": "Mon Apr 14 23:37:41 2014", "token-id": "l3CvWcEr5rKvooOaCymFvy2qp3cY18XCs4JrW4EvPww=", "link": "https://mywebsite/api/v1/auth/token-services/1634484805"}
NOW MY QUESTION is, how to achieve this using python. WHAT libraries i should use? i need to extract the token-id from the json response. so that i will use that token for further request to consume REST services.
if some one can post the PYTHON code snippet for this that would be great.
Have a look at the following HOWTO of the python documentation: HOWTO Fetch Internet Resources Using urllib2. There you also find a section with an code example for Basic authentication. The HOWTO describes how you can use the module urllib2.
Other useful libraries:
requests
mechanize
I got the solution for what i am looking for...
Complete Sample code ...
import requests
from requests.auth import HTTPBasicAuth
import json
token = ""
def get_token(username, password, url):
global token
#verify=False will not verify the ssl
resp = requests.post(url, auth=HTTPBasicAuth(username, password), verify=False)
print "\n", dir(resp)
print "Status Code:", resp.status_code, "\n"
print "text:", resp.text, "\n"
print "json:", resp.json(), "\n"
print "Content:", resp.content, "\n"
print "Headers:", resp.headers, "\n"
print "Header(Content-type:)", resp.headers.get('content-type'), "\n"
print "Header(Content-length:)", resp.headers.get('content-length'), "\n"
print "OK:", resp.ok, "\n"
print "json dump:", json.dumps(resp.json())
json_dict = json.loads(resp.text)
token = json_dict['token-id']
print "\ntoken-id:", json_dict['token-id']
for key, value in json_dict.items():
print key, "=>", value
return token
def get_global_users(token):
print "\nexecuting get_global_users.."
print "Token", token
url = 'https://xxx.xxx.xxx.xxx/api/v1/global/users'
headers_dict = {'content-type': 'application/json', 'Accept': 'application/json', 'X-Auth-Token': token}
resp = requests.get(url, headers=headers_dict, verify=False)
print "Status Code:", resp.status_code, "\n"
print "text:", resp.text, "\n"
print "json:", resp.json(), "\n"
json_users = json.loads(resp.text)
print "all users:\n", json_users['users']
print "\n"
for users in json_users['users']:
for key, value in users.items():
print key, "=>", value
def post_global_user(token):
print "\nexecuting post_global_users.."
print "Token:", token
url = 'https://xxx.xxx.xxx.xxx/api/v1/global/users'
headers_dict = {'content-type': 'application/json', 'Accept': 'application/json', 'X-Auth-Token': token}
payload = {'username': 'myuser', 'password': 'pas1234', 'pw-type': 0, 'privilege': 15}
resp = requests.post(url, data=json.dumps(payload), headers=headers_dict, verify=False)
print "Status Code:", resp.status_code, "\n"
To emulate the curl command:
$ curl -v --user username:pass1234 -H "accept: application/json" \
-X POST -d "" https://mywebsite/api/v1/auth/token-services --insecure
in Python using only stdlib:
#!/usr/bin/env python
import base64
import json
from urllib2 import urlopen, Request
credentials = base64.b64encode(b'username:pass1234')
headers={'Authorization': b'Basic ' + credentials,
'Accept': 'application/json'}
response = urlopen(Request("https://example.com/post", b"", headers))
data = json.load(response)
token_id = data["token-id"]
If you want to see what is sent to/received from a server for https requests; enable debugging:
import urllib2
urllib2.install_opener(urllib2.build_opener(urllib2.HTTPSHandler(debuglevel=1)))
Related
I am using requests to make a POST request to create a user. The request succeeds with 201 created when I use curl, however fails with a 500 response when I use requests. My curl command is
curl --user administrator:password -H "Content-Type: application/json" https://localhost:8080/midpoint/ws/rest/users -d #user.json -v
And my python script is:
import requests
import json
headers = {
'Content-Type': 'application/json',
}
with open('user.json') as j:
data = json.load(j)
response = requests.post('https://localhost:8080/midpoint/ws/rest/users', headers=headers, data=str(data), auth=('Administrator', 'password'))
print(response)
Can anyone see a reason why my python script would be failing? I am at a loss.
str(data) returns the Python representation of data, not its JSON representation. These two forms can differ in things like ' vs. ", True vs. true, and None vs. null. To properly JSONify data, call json.dumps() on it:
response = requests.post(..., data=json.dumps(data))
or let requests do the JSONification:
response = requests.post(..., json=data)
or use the JSON as it appears in user.json directly:
with open('user.json') as j:
data = j.read()
response = requests.post(..., data=data)
I'm working with Dropbox's python API, trying to convert the following curl command to Python Requests:
curl -X POST https://content.dropboxapi.com/2/files/download \
--header "Authorization: Bearer <ACCESS_TOKEN>" \
--header "Dropbox-API-Arg: {\"path\": \"/Homework/math/Prime_Numbers.txt\"}"
My translation so far:
downloadHeader={"Authorization: " + authorization}
downloadURL = "https://content.dropboxapi.com/2/files/download"
downloadPayload = {"Dropbox-API-Arg": {"path": "/" + dbPATH}}
downloadResponse = requests.post(downloadURL, data=json.dumps(downloadPayload), headers=downloadHeader)
However, when I run this I get the following error:
for header in headers.items():
AttributeError: 'set' object has no attribute 'items'
Can anyone give me some feedback? I'm confident about my authorization value because it's working in a separate request which I'm copy and pasting below:
MDlink = "https://api.dropboxapi.com/2/sharing/get_shared_link_metadata"
authorization = "Bearer " + ACCESS_TOKEN
headers={"Content-Type":"application/json", "Authorization": authorization}
payload = {"url": imageLink}
response = requests.request("POST", MDlink, data=json.dumps(payload), headers=headers)
Thank you very much!
You want this
downloadHeader={"Authorization: " + authorization}
To be
downloadHeader={"Authorization": authorization}
Or more precisely
downloadHeader={"Authorization": "Bearer <ACCESS_TOKEN>"}
Explanation:
{1} # this is a set. It has no .items()
{1: 1} # this is a dict. You can call .items()
I'm trying to request access tokens from the fitbit API, but it keeps returning 401 Unauthorized status, even though I configure the request identical to a corresponding curl query - which succeeds. The error message returned says: "errorType":"invalid_client","message":"Invalid authorization header format. Is there some nuance of how httplib2 builds its requests that is throwing me off here?...
(Working) curl query:
curl -X POST -i
-H 'Authorization: Basic <LONG_CODE>'
-H 'Content-Type: application/x-www-form-urlencoded'
-d "clientId=<CLIENT_ID>"
-d "grant_type=authorization_code"
-d "redirect_uri=http%3A%2F%2F127.0.0.1%3A5000%2Ffitbit-callback"
-d "code=<AUTHORIZATION_GRANT_CODE>"
https://api.fitbit.com/oauth2/token
Non-working python request (edited):
TOKEN_URL = 'https://api.fitbit.com'/oauth2/token'
CALLBACK_URI = 'http://127.0.0.1:5000/fitbit-callback'
auth_header = base64.b64encode(bytes(<CLIENT_ID> + ':' + <CLIENT_SECRET>, 'utf-8'))
headers = {
'Authorization': 'Basic %s' % auth_header,
'Content-Type' : 'application/x-www-form-urlencoded'
}
params = {
'client_id': <CLIENT_ID>,
'grant_type': 'authorization_code',
'redirect_uri': CALLBACK_URI,
'code': <AUTHORIZATION_GRANT_CODE>
}
urlparams = urlencode(params)
resp, content = h.request(TOKEN_URL,
'POST',
urlparams,
headers)
Not evident from code:
the auth_header-variable in python matches <LONG_CODE>
Terminal response after python3 fitbit.py:
send: b"POST /oauth2/token HTTP/1.1\r\nHost: api.fitbit.com\r\nContent-Length: 153\r\nauthorization: Basic b'<LONG_CODE>'\r\ncontent-type: application/x-www-form-urlencoded\r\nuser-agent: Python-httplib2/0.10.3 (gzip)\r\naccept-encoding: gzip, deflate\r\n\r\n"
send: b'client_id=<CLIENT_ID>&grant_type=authorization_code&redirect_uri=http%3A%2F%2F127.0.0.1%3A5000%2Ffitbit-callback&code=<AUTHORIZATION_GRANT_CODE>'
reply: 'HTTP/1.1 401 Unauthorized\r\n'
header: Date header: Content-Type header: Transfer-Encoding header: Connection header: Cache-control header: WWW-Authenticate header: Content-Language header: Content-Encoding header: Vary header: X-Frame-Options header: Server header: CF-RAY
Running print(content):
b'{"errors":[{"errorType":"invalid_client","message":"Invalid authorization header format. Visit https://dev.fitbit.com/docs/oauth2 for more information on the Fitbit Web API authorization process."}],"success":false}'
Well this is awkward. I didn't notice it before I directed the requests towards a request capture service that let me analyze them (like runscope), but I seem to simply have missed the b'<LONG_CODE>' formatting in the python example. This fixed it:
auth_header.decode("utf-8")
Maybe this question should be deleted, if it is unlikely to help anyone else...
When trying out the digitalocean v2 api I come across the following behaviour:
curl -X POST "https://api.digitalocean.com/v2/droplets" \
-d'{"name":"t002","region":"ams3","size":"512mb","image":"debian-7-0-x64","ssh_keys":[123]}' \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json"
Works fine and the droplet gets created.
Now when I do call it from python with:
json_values = {'name': 's002', 'region': 'ams3', 'size': '512mb', 'image': 'debian-7-0-x64', 'ssh_keys': [123]}
data = urllib.parse.urlencode(json_values)
data = data.encode("utf-8")
try:
req = urllib.request.Request(create_droplets_url, data)
req.add_header("User-Agent", uagent) # set custom user agent
req.add_header("Authorization", BearerToken) # set custom user agent
response = urllib.request.urlopen(req)
I get back: HTTP Error 422: Unprocessable Entity with no further information. Am i doing something wrong on the python side? Thx
Additional Info:
I figured out that the problem must be with ssh_keys. If I remove that element everything works fine.
Why are you url-encoding the data? That's not what the curl version is doing. Dump it to JSON instead:
data = json.dumps(json_values)
req = urllib.request.Request(create_droplets_url, data)
I have received the same error and realized it has occurred due to the server side validation failed with your post data.
Solution:
use requests.post instead of urllib.request.Request then you could get the accurate error message for that serverside 422 error code.
Sample code:
import requests
API_URL = "***"
TOKEN = "***"
HEADERS = {
"User-Agent": "Python API Sample",
"Authorization": "Bearer " + TOKEN,
"Content-Type": "application/json"
}
data = {
"user_id": "***",
"project_id": "***"
}
json_data = json.dumps(data).encode('utf8')
response = requests.post(url=API_URL, headers=HEADERS, data=json_data)
print(json.dumps(json.loads(response.text), sort_keys=True, indent=4, separators=(",", ": ")))
Thanks :)
I'm trying to integrate PayPal REST API in my website. As a first step, I'm trying to translate cURL commands into Python and I'm getting an Exception Value: HTTP Error 400.
The code I'm using (is based on https://stackoverflow.com/a/2003832/2675537):
def basic_authorization(user, password):
s = user + ":" + password
return "Basic " + s.encode("base64").rstrip()
req = urllib2.Request("https://api.sandbox.paypal.com/v1/oauth2/token",
headers = {
"Authorization": basic_authorization("EBWKjlELKMYqRNQ6sYvFo64FtaRLRR5BdHEESmha49TM", "EO422dn3gQLgDbuwqTjzrFgFtaRLRR5BdHEESmha49TM"),
"Accept": "application/json",
"Accept": "*/*",
"User-Agent": "my-python-app/1",
},
data = '{"message":{"body":' + 'grant_type=client_credentials' + '}}' )
f = urllib2.urlopen(req)
return HttpResponse(f)
which is the equivalent (I guess) to:
curl https://api.sandbox.paypal.com/v1/oauth2/token \
-H "Accept: application/json" \
-u "EBWKjlELKMYqRNQ6sYvFo64FtaRLRR5BdHEESmha49TM:EO422dn3gQLgDbuwqTjzrFgFtaRLRR5BdHEESmha49TM" \
-d "grant_type=client_credentials"
And the traceback is here: (Edit: Broken Link)
According to PayPal I should get a response like this:
{"scope":"https://api.paypal.com/v1/payments/.* https://api.paypal.com/v1/vault/credit-card https://api.paypal.com/v1/vault/credit-card/.* https://api.paypal.com/v1/developer/.*","access_token":"OABI8rm75u.5EIuK7.JrI2sLhnv3rhDgLElKAwTfyys","token_type":"Bearer","app_id":"APP-2EJ531395M785864S","expires_in":28800}
Is there an error in my code? Is there a better way to do it?
First of all, I would suggest you not to post your keys in clear text in your code examples.
The error your getting "HTTP Error 400: Bad Request", is due to a badly formed request.
From the docs the format for a request is:
urllib2.Request(url[, data][, headers][, origin_req_host][, unverifiable])
data may be a string specifying additional data to send to the server,
or None if no such data is needed.
headers should be a dictionary, and will be treated as if add_header()
was called with each key and value as arguments.
So your data field is passing a dict instead of string, and it would be a lot more readable
if you separated the fields outside of the Request class. When you have multiple header
fields to fill in, I find it better to use the add_header method as shown below.
import urllib, urllib2
def basic_authorization(user, password):
s = user + ":" + password
return "Basic " + s.encode("base64").rstrip()
url = "https://api.sandbox.paypal.com/v1/oauth2/token"
params = { "grant_type": client_credentials}
data = urllib.urlencode(params)
req = urllib2.Request(url, data)
req.add_header("Authorization",basic_authorization("XXX"))
req.add_header("Accept", "application/json")
req.add_header("User-Agent", "my-python-app/1")
response = urllib2.urlopen(req)