Using Python request post method but getting 401 response code - python

I am using Python request module post method to process json data, like so.
r = requests.post(url,data=json.dumps(payload),headers=headers)
However I am getting response[401]. Does it mean I need to first authorize it
by adding login first?

A 401 response, as you noticed, means that you need to authenticate in order to make the request. How you do this depends on the auth system in place, but your comment "I use HTTPBasicAuth(user, password) that give me response code of 200" suggests that it's just Basic Auth - which is easy to deal with in requests.
Anywhere you do a requests call, add the kwarg auth=(USERNAME, PASSWORD) - so for your example above, you'd do r = requests.post(url,data=json.dumps(payload),headers=headers, auth=(USERNAME, PASSWORD)) (replacing USERNAME and PASSWORD with the right values, as shown here.

Related

Automatically getting Mojang bearer token

I am writing a program that can change your Mojang username at whatever time you specify (i.e. the name "tom" becomes available at 09:05:39 so you would set the program to change your name to "tom" at that time). To do this you need a bearer token. I can log into minecraft.net and use EditThisCookie to access that, but I want to be able to have the program wait until it is within a minute of the name dropping to gather proxies and the bearer token automatically for situations where a name is becoming available in the middle of the night or I'm just lazy. I'm not sure why my function for getting the bearer token won't work. I referenced this to write this code.
def getAT():
jsonForAT = json.dumps({"agent":{"name":"Minecraft","version":1},"username":email,"password":password,"clientToken":""})
headersForAT = {'Content-Type': 'application/json'}
requestForAT = requests.post('https://authserver.mojang.com/authenticate', data=jsonForAT, headers=headersForAT)
pullATRequestData = requestForAT.json()
AT = pullATRequestData["accessToken"]
return AT
I am really confused since when I use this, I get a 401 error but the program works when I get the token manually.
I also was experiencing the same issue. Then, I realized that Minecraft/Mojang accounts have security questions. If your function is getting the bearer token and your issue is that your access is denied when posting a name change request:
1st make sure your formatting it properly:
headers={'Authorization': f"Bearer {TOKEN}"
Notice the space between "Bearer" and {TOKEN}
2nd: For some reason, Mojang needs you to send a Get request to their security challenges endpoint. You don't have to do anything with the returned data..
When you got the token manually, I'm assuming your browser automatically sent this get request and that's why it worked. If you're using proxies, you'll probably need to send a post request with your security question answers, look at the API link for documentation.
For Example:
res = requests.get(
"https://api.mojang.com/user/security/challenges",
headers={"Authorization": f"Bearer {TOKEN}"},
)
https://wiki.vg/Mojang_API
Go to the bottom under "Security question-answer flow"

curl to python requests error: "no api key supplied"

I'm trying to do a curl command with python requests. As far as I can tell I'm doing everything correctly but the website won't recognize the api key no matter how I try to include it. Basically, the site I'm trying to reach wants the api key put in the beginning of the url. When I do this with curl, it works perfectly. When I try it via python requests, however, it doesn't work. It also doesn't work to send it in as a key-value pairing in dictionary.
This works
curl -H "Content-Type:application/json" -d '{"ndbno":["11124"],"type":"f"}' [API KEY]#api.nal.usda.gov/ndb/V2/reports
and here's the requests code:
import requests
headers = {'Content-Type': 'application/json',}
data = '{"ndbno":["11124"],"type":"f"}'
response = requests.post('http://[API KEY]#api.nal.usda.gov/ndb/V2/reports', headers=headers, data=data)
The result from this is a json response containing the message: "{'error': {'code': 'API_KEY_MISSING', 'message': 'No api_key was supplied. Get one at http://api.nal.usda.gov:80'}}
"
It also doesn't work if I remove the [API KEY] from the url and add it to the data dictionary as "api_key":"[API KEY]"
BTW I'm not passing the key in as a list or anything, I just didn't want to post the physical key in my question.
I'm a total newb to python and stackoverflow, but I've done my due diligence and have been searching out answers and testing different ways to format the request for a few hours now. Any help is greatly appreciated!
Looking at the PubAG API, it appears that you can simply pass the api_key in the URL query string. I'd assume it's the same for the API you're using, but a cursory search yielded no documentation.
Try:
https://api.nal.usda.gov/ndb/V2/reports?api_key=[API_KEY]
response = requests.post('https://api.nal.usda.gov/ndb/V2/reports?api_key=[API_KEY]', headers=headers, data=data)
I don't have an API key to try this out with, but navigating to https://api.nal.usda.gov/ndb/V2/reports?api_key=asdfds in my browser gives me an invalid API key error, which suggests that the endpoint recognizes that I've given an API key.
It's probably because requests does not parse the API KEY from the URL, try this:
response = requests.post('http://api.nal.usda.gov/ndb/V2/reports', headers=headers, data=data, auth=(API_KEY, ''))
This passes it using Basic Authentication (Authorization header) which is the same behavior that curl does when parsing the URL.
Normally in Basic Auth you would have the username and the password. E.g:
auth=('<username>', '<password>')
Since this API only seems to care about the username, I have left the password as blank.

Requests works and URLFetch doesn't

I'm trying to make a request to the particle servers in python in a google app engine app.
In my terminal, I can complete the request simply and successfully with requests as:
res = requests.get('https://api.particle.io/v1/devices', params={"access_token": {ACCESS_TOKEN}})
But in my app, the same thing doesn't work with urlfetch, which keeps telling me it can't find the access token:
url = 'https://api.particle.io/v1/devices'
payload = {"access_token": {ACCESS_TOKEN}}
form_data = urllib.urlencode(payload)
res = urlfetch.fetch(
url=url,
payload=form_data,
method=urlfetch.GET,
headers={
'Content-Type':
'application/x-www-form-urlencoded'
},
follow_redirects=False
)
I have no idea what the problem is, and no way to debug. Thanks!
In a nutshell, your problem is that in your urlfetch sample you're embedding your access token into the request body, and since you're issuing a GET request -which cannot carry any request body with them- this information gets discarded.
Why does your first snippet work?
Because requests.get() takes that optional params argument that means: "take this dictionary I give you, convert all its key/value pairs into a query string and append it to the main URL"
So, behind the curtains, requests.get() is building a string like this:
https://api.particle.io/v1/devices?access_token=ACCESS_TOKEN
That's the correct endpoint you should point your GET requests to.
Why doesn't your second snippet work?
This time, urlfetch.fetch() uses a different syntax than requests.get() (but equivalent nonetheless). The important bit to note here is that payload argument doesn't mean the same as our params argument that you used before in requests.get().
urlfetch.fetch() expects our query string -if any- to be already urlencoded into the URL (that's why urllib.urlencode() comes into play here). On the other hand, payload is where you should put your request body in case you were issuing a POST, PUT or PATCH request, but particle.io's endpoint is not expecting your OAuth access token to be there.
Something like this should work (disclaimer: not tested):
auth = {"access_token": {ACCESS_TOKEN}}
url_params = urllib.urlencode(auth)
url = 'https://api.particle.io/v1/devices?%s' % url_params
res = urlfetch.fetch(
url=url,
method=urlfetch.GET,
follow_redirects=False
)
Notice how now we don't need your previous Content-type header anymore, since we aren't carrying any content after all. Hence, headers parameter can be removed from this example call.
For further reference, take a look at urlfetch.fetch() reference and this SO thread that will hopefully give you a better insight into HTTP methods, parameters and request bodies than my poor explanation here.
PS: If particle.io servers support it (they should), you should move away from this authentication schema and carry your tokens in a Authorization: Bearer <access_token> header instead. Carrying access tokens in URLs is not a good idea because they are much more visible that way and tend to stay logged in servers, hence posing a security risk. On the other hand, in a TLS session all request headers are always encrypted so your auth tokens are well hidden there.
Ok, so, as it turns out, one cannot include a payload for a GET request using Urlfetch. Instead, one has to include the parameters in the url using the '?' syntax as follows:
url = 'https://api.particle.io/v1/devices'
url = url + '?access_token=' + {ACCESS_TOKEN}
res = urlfetch.fetch(
url=url,
method=urlfetch.GET,
follow_redirects=False
)
this worked for me.

Yggdrasil authentication with Python

I decided to try to make an automated login script for Minecraft. However, the new authentication API is stumping me. I can't find any mentions of the new functionality of the API on here. This is my code as it stands:
import requests
import json
data = json.dumps({"agent":{"name":"Minecraft","version":1},"username":"abcdef","password":"abcdef","clientToken":""})
headers = {'Content-Type': 'application/json'}
r = requests.post('https://authserver.mojang.com', data=data, headers=headers)
print (r.text)
Unfortunately, this returns:
{"error":"Method Not Allowed","errorMessage":"The method specified in the request is not allowed for the resource identified by the request URI"}
According to this resource on request format, this error means that I didn't correctly send a post request. However, I clearly declared requests.post(), so my first question is how am I incorrect, and what is the correct way to go about this?
My second question is, since I'm relatively new to Python and JSON, how would I replace the username and password fields with my own data, inside a variable?
You haven't specified an endpoint in your POST request, for example:
https://authserver.mojang.com/authenticate
The root of the website probably does not accept POST requests
http://wiki.vg/Authentication#Authenticate

Cookie for Google App Engine request - Python

I'm working on an app which uses an API that requires me to make a first Post request to authenticate.
Looking the authenticate response, I've seen that a cookie was created: ApiCredentials=....
So I authenticate:
result = urlfetch.fetch(url = url, method = urlfetch.POST)
api_credential = result.headers['set-cookie']
and then I create a request with that cookie in the header
urlfetch.fetch(url = url, method = urlfetch.GET, headers = {'Cookie': api_credential})
The problem is: in dev everything works perfectly, but when I deploy, it doesn't work. In the logs I can see the cookie that was recieved.
API link: http://www.sptrans.com.br/desenvolvedores/APIOlhoVivo/Documentacao.aspx?1 (portuguese)
The code in the question does not show the cookie name ApiCredentials. It may be that in development, there was only a single cookie and in production there are more, in which case result.headers['set-cookie'] returns multiple values comma separated.
The URL Fetch Response Objects page suggests retrieving multiple headers of the same name in a list by calling result.header_msg.getheaders('set-cookie') instead and then finding ApiCredentials in the resulting list.
It might be safer to say 'Set-Cookie' in case-sensitive environments.

Categories

Resources