Post request using Python urllib - python

I'm making a request to an api using python3 urllib. This is my code,
headers = {}
headers['Content-Type']='application/x-www-form-urlencoded; charset=UTF-8'
#headers['X-Csrf-Token']= {'mode: cors'}
req = urllib.request.Request(url=URL, headers=headers, method='POST')
res = urllib.request.urlopen(req)
print(res.read())
I get the following response,
urllib.error.HTTPError: HTTP Error 415: Unsupported Media Type
The API endpoint is working fine and I've tested it with Postman. This is the equivalent javascript code which gets the job done,
return fetch(url, { credentials : 'include', method: 'post'})
So I'm assuming I've to find a way to add credentials to the header. Can I do a credentials include parallel in Python or do I have to fetch the specific cookie and set it in the request. Any help appreciated.

The error 415 indicates an issue with 'Content-type'.
'application/x-www-form-urlencoded' does not have any parameters.
https://www.w3.org/TR/html5/iana.html#application/x-www-form-urlencoded
Regarding fetch()'s "credentials", you would need the ability to maintain a session (sending cookies as required).
It is much easier with the requests library's Session
http://docs.python-requests.org/en/master/user/advanced/#session-objects

Related

Python request gives 415 error while post data

I am getting 415 error while posting data to server. This is my code how can i solve this problem. Thanks in advance!
import requests
import json
from requests.auth import HTTPBasicAuth
#headers = {'content-type':'application/javascript'}
#headers={'content-type':'application/json', 'Accept':'application/json'}
url = 'http://IPadress/kaaAdmin/rest/api/sendNotification'
data = {"name": "Value"}
r = requests.post(url, auth=HTTPBasicAuth('shany.ka', 'shanky1213'),json=data)
print(r.status_code)
According to MDN Web Docs,
The HTTP 415 Unsupported Media Type client error response code
indicates that the server refuses to accept the request because the
payload format is in an unsupported format.
The format problem might be due to the request's indicated
Content-Type or Content-Encoding, or as a result of inspecting the
data directly.
In your case, I think you've missed the headers.
Uncommenting
headers={
'Content-type':'application/json',
'Accept':'application/json'
}
and including headers in your POST request:
r = requests.post(
url,
auth=HTTPBasicAuth('shany.ka', 'shanky1213'),
json=data,
headers=headers
)
should do the trick
import requests
import json
from requests.auth import HTTPBasicAuth
headers = {
'Content-type':'application/json',
'Accept':'application/json'
}
url = 'http://IPadress/kaaAdmin/rest/api/sendNotification'
data = {"name": "Value"}
r = requests.post(
url,
auth=HTTPBasicAuth('shany.ka', 'shanky1213'),
json=data,
headers=headers
)
print(r.status_code)
As a workaround, try hitting your api using Postman. When you can successfully hit the api in postman, generate python code in postman (button is present in the top right corner). You can copy the code in your python project.
Another possible cause is using requests.post when you should be using requests.get or vice versa. I doubt that this is a common problem, but in my case a server that was happy to accept an HTTP GET for a search rejects it with a 415 when HTTP POST is used instead. (Yet another site required that a search be requested using HTTP POST. It was reusing that code that caused my problem.)

OAuth1 Authentication of Rest API

I need to do a post request according to the scenario given below. I only have consumers_key and consumer_secret. I don't know from where to get all the other fields. and also do i need to send the Authorization request including keys in the header?
A request token for the application must be obtained using the consumer key from the above response.
Request
POST /public/v1/oauth1/request_token
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Authorization: OAuth
oauth_consumer_key="btgd2cg2bm3lbjqsfv150fj9q8",
oauth_signature_method="HMAC-SHA1",
oauth_timestamp="1467792887",
oauth_nonce="9fd50a6f-40e0-41be-8809-34aa832b688e",
oauth_callback="oob",
oauth_signature="hcE6Q3boTytkHmM72xegCP1Y3W4%3D"
I am doing something like this
import requests
url="https://api.discovergy.com"
request_token_url=url+'/public/oauth1/request_token'
head={'Accept':'text/html, image/gif, image/jpeg, *;q=.2, '/';q=.2',
'Authorization':'OAuth'}
data= dict(oauth_consumer_key=client_key, oauth_signature_method='HMAC-SHA1', oauth_timestamp='1467792887', oauth_nonce='9fd50a6f-40e0-41be-8809-34aa832b688e', oauth_callback='oob', oauth_signature='hcE6Q3boTytkHmM72xegCP1Y3W4%3D')
r=request.post(url=request_token_url, data=data, headers=head)
print(r.content)
It gives 400 status..
Oauth1 has a different authorisation building module in python for Requests. See that documentation and the help files for examples of use.
The 400 RC you get is because you try to POST to that endpoint and the method is not supported. Most likely you can only GET from there.
The Discovergy API docs are at https://api.discovergy.com/docs/. I've setup a small PHP Discovergy API client at https://github.com/andig/discovergy. It demonstrates the entire process. For the /request_token POST (it is a POST) make sure to use the consumer key obtains from /consumer_token, not the credentials provided by Discovergy.
Update I've also noticed that according to your example you seem to pass the parameters as POST body. These need to be in the header as in the first code block you've shown.
Update 2 Also make sure to accept the right content types, at least application/json, maybe plus text/plain
 Recent versions does not have problem to request authentication using OAuth1 from request_oauthlib
from requests_oauthlib import OAuth1, OAuth1Session
OAUTH = OAuth1(API_KEY, API_KEY_SECRET, ACCESS_TOKEN, ACCESS_TOKEN_SECRET)
HEADERS = {'Content-Type': 'application/json', 'Accept': '*/*'}
requests.method(url, data=json.dumps(payload), headers=HEADERS, auth=OAUTH)

Is this a Post request issue or an SSL verification issue

I'm trying to use a certain company's (not yet public) API. In their documentation they lay out the format of the Token request. Here's a copy of the documentation for a Token request:
POST
https://***.****.com/auth/realms/****/protocol/openid-connec
t/token
Headers:
Content-Type: application/x-www-form-urlencoded
Authorization: Basic {base64-encoded-key-and-secret}
Body: grant_type:client_credentials
The authorization key was given to me by them and is of the form 'Basic a3RhdmlfdG...'
I'm trying to write a Post request in python and I'm having issues and I'm not sure if it's my fault or their developers fault. Here's my code:
url = 'https://***.****.com/auth/realms/****/protocol/openid-connect/token'
headers = {'Content-Type':'application/x-www-urlencoded', 'Authorization':'Basic a3RhdmlfdG...'}
body = {'grant_type':'client_credentials'}
response = requests.post(url = url, data = json.dumps(body), headers = headers)
print response
At the line where response = ...I'm getting an SSL: CERTIFICATE_VERIFY_FAILED error. I've also tried changing the values in the headers to random values and I get the same error. I can think of three possibilities, either
I'm making the Post request incorrectly
There is a problem with the API
I'm missing a certificate which I have to send with the Post request
Is it one of these issues or is it something else?
They are probably using a self signed cert. You can bypass the verify check by adding 'verify=False'. I would remove that before going to production. It is important that SSL certs are valid.
response = requests.post(url = url, data = json.dumps(body), headers = headers, veryify=False)

Django rejects Requests' CSRF Token

I'm writing an Ajax post with python's Request's library to a django backend
Code:
import requests
import json
import sys
URL = 'http://localhost:8000/'
client = requests.session()
client.get(URL)
csrftoken = client.cookies['csrftoken']
data = { 'file': "print \"It works!\"", 'fileName' : "JSONtest", 'fileExt':".py",'eDays':'99','eHours':'1', 'eMinutes':'1' }
headers = {'Content-type': 'application/json', "X-CSRFToken":csrftoken}
r = requests.post(URL+"au", data=json.dumps(data), headers=headers)
Django gives me a 403 error stating that the CSRF token isn't set even though the request.META from csrf_failure() shows it is set. Is there something I'm missing or a stupid mistake I'm not catching?
I asked my friend and he figured out the problem, basically you have to send the cookies that django gives you every time you do a request.
corrected:
cookies = dict(client.cookies)
r = requests.post(URL+"au", data=json.dumps(data), headers=headers,cookies=cookies)
You need to pass the referer to the headers, from the django docs:
In addition, for HTTPS requests, strict referer checking is done by
CsrfViewMiddleware. This is necessary to address a Man-In-The-Middle
attack that is possible under HTTPS when using a session independent
nonce, due to the fact that HTTP ‘Set-Cookie’ headers are
(unfortunately) accepted by clients that are talking to a site under
HTTPS. (Referer checking is not done for HTTP requests because the
presence of the Referer header is not reliable enough under HTTP.)
so change this:
headers = {'Content-type': 'application/json', "X-CSRFToken":csrftoken, "Referer": URL}

Accessing Imgur API with Python 3.4.1 and Urllib3

I am trying to wrap my head around the Imgur API. I have found some good examples of how to send the authorization header to Imgur, however they all use urllib2, and I apparently, using pyhton 3.4.1 can only use urllib3.
So I have tried a couple of things and none of them seem to be working.
from this post I tried using the basic_auth header:
http = urllib3.PoolManager()
header = urllib3.make_headers(basic_auth="Client-ID" + CLIENT_ID)
r = http.request('GET', 'https://api.imgur.com/3/gallery/r/pics', headers=header)
that gives me a 403 error.
from this post I tried this method instead:
http = urllib3.PoolManager()
header= {"Content-Type": "text", "Authorization": "Client-ID" + CLIENT_ID}
r = http.request('GET', 'https://api.imgur.com/3/gallery/r/pics', headers=header)
that also returns a 403.
Now however I have got a step closer by reading the urllib3 documents and tried sending the Authorization as a field instead.
http = urllib3.PoolManager()
r = http.request('GET', 'https://api.imgur.com/3/gallery/r/pics', fields={"Authorization": "Client-ID " + CLIENT_ID})
this however returns a 401.
so can some one help me to figure out basic anonymous interaction with the Imgur API using these, or other methods?
Per imgur's API documentation, you have to send the auth header as such:
Authorization: Client-ID YOUR_CLIENT_ID
In this line:
header = urllib3.make_headers(basic_auth="Client-ID" + CLIENT_ID)
you are sending it as:
Authorization: Client-IDYOUR_CLIENT_ID
You need a space between.

Categories