I'm trying to get the oauth request_token for Twitter as described here, making a call to "oauth/request_token": https://dev.twitter.com/docs/auth/implementing-sign-twitter
I'm generating the params using the encode_params function in here: https://github.com/sixohsix/twitter/blob/master/twitter/oauth.py
I then wrap the returned string in a dict with they key "Authorization" and dump it into the Headers of the Post request I'm making using the python request library. Here's the two lines I use to create the request.
ep = "OAuth " + auth.encode_params(baseUrl, method, params)
response = requests.post(baseUrl+method, headers={ "Authorization" : ep})
The eventual header looks like this (consumer_key modified):
{'Accept': '*/*',
'Accept-Encoding': 'gzip, deflate, compress',
'Authorization': 'OAuth oauth_callback=http%253A%252F%252Fec2-54-244-189-248.us-west-2.compute.amazonaws.com%252Fct%252Ftwitter_login_handler%252F&oauth_consumer_key=xxx&oauth_nonce=14937468581358710045&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1366568033&oauth_version=1.0&oauth_signature=kiYucZzPY%2FXy2WyJliJ6YcggVzQ%3D',
'Content-Length': '0',
'User-Agent': 'python-requests/1.2.0 CPython/2.7.3 Linux/3.5.0-21-generic'}
However, I'm still getting a 401 response that says: 'Failed to validate oauth signature and token'
Any idea what I'm doing wrong? Any help would really be appreciated.
I can't speak to the script you reference, but if you're willing to try another library as the author of rauth I can recommend it. Here's a working Twitter example. Hope that helps.
I ended up using python-oauth2. Their instructions were a little out of date, so I updated them and submitted a pull request. As of right now, it's not been accepted, but here's a link to the forked repo with the updated instructions.
Hopefully this helps someone else...
From the code referenced by maxcountryman - it has a comment that I had not found elsewhere till then :
# Get a real consumer key & secret from https://dev.twitter.com/apps/new
That helped me progress a lot...
Cheers, Ian
.
Related
I have an API I am building out that will allow me to upload media to my WordPress website using their new API. I have searched all over the internet and SO for a solution to this problem, but all of the answers seem to be using an older WordPress API so I have not had much success in finding an answer.
I have the following code written out in a function to send a multipart/form-data request to the API:
img = open(image_path, 'rb')
file_name = os.path.basename(image)
print('Compressing and sending data...')
NEW_HEADER = {
'Authorization': f'BEARER {WORDPRESS_ACCESS_TOKEN}',
'Content-Disposition': f'attachment; filename={file_name}',
'Content-Type': 'multipart/form-data'
}
response = requests.post(
url=WORDPRESS_MEDIA_URL,
files={'media': img.read()},
headers=NEW_HEADER
)
print(response.request)
print(response.text)
return response
Which returns me:
{"media":[],"errors":[]}
<Response [200]>
OK
So, it sends something to the endpoint, but it's return an empty array and empty error box. Again, I can't seem to find any solution for the new WP, so forgive me if the Python seems a little hacky and put-together, I've just been putting together what appears to work.
Further Reading Since Original Posting
I pinged the API with Postman and it returns data as expected:
{"media":[{"id":"xxxx","date":"2022-11-03T20:06:54-05:00","parent":0,"link":"https:mywebsite","title":"mypicture","caption":"","description":"",...}
So, Since the post request seems to not be the issue, I tried to debug my request in Postman and my local console to see what was being sent:
{'User-Agent': 'python-requests/2.28.1', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Authorization': 'BEARER QnkXS43KhiqO7Oa!9G!zN2gnz90hHhZEribF2ddZu0h8&5V0p5M69^OwDb9E6H%B', 'Content-Type': 'multipart/form-data', 'Content-Length': '6'}
media=
And I see that the media returns empty from my local console. In Postman, the media is returned as undefined (though I'm not sure if that's just Postman being unable to parse the image in a JSON format in the console/debugger.
This leads me to believe that either the way I am accessing/calling the directory with the image is wrong, or the way I am trying to encode it to the request.
Even Further Reading Since Posting
I have since circumnavigated any concerns about directory issues by copying the photos from an external directory to that of one inside the project folder.
Since then, it appears that the current way I am sending the data returns the same response as if I am sending nothing at all:
response = requests.post(
url=WORDPRESS_MEDIA_URL, # there is no data sent in this request.
headers=NEW_HEADER
)
Which still returns me:
{"media":[],"errors":[]}
<Response [200]>
OK
This leads me to believe that the way I am sending the data is incorrect, as WordPress is receiving my request, but is not getting the information that it needs.
So, doing some further reading and research, I come across requests-toolbelt, which is to help sending multipart/form-data:
data = MultipartEncoder(fields={'media': (file_name, img, 'image/jpeg')})
new_header = {
'Authorization': f'BEARER {WORDPRESS_ACCESS_TOKEN}',
'Content-Type': data.content_type,
'Content-Disposition': 'form-data; name="media"; filename="%s"' % name_img,
}
response = requests.post(WORDPRESS_MEDIA_URL, data=data, headers=new_header)
Now, when I send a request with this data, I get this response:
{"error":"unsupported_mime_type","message":"File type unknown"}
<Response [400]>
Bad Request
So sending the request with the MultipartEncoder returns an error of an unsupported MIME type. So while it isn't a blank 200 response, it gives me reason to think that perhaps I am using the MultipartEncoder wrong, or I am not making the proper adjustments to the picture I am trying to upload.
Any insight into this would be greatly appreciated.
I'm trying to make a post request to our app's api for some regression testing, but for some reason when I make the request like so through requests, it's logged and interpreted as a GET request.
CODE:
requests.post({HTTP_PROTOCOL}://{APP_URL}/api/route/',
headers={'Authorization': 'Bearer ' + access_token},
json=DATA)
LOG:
[Thu Jul 11 19:17:30 2019] GET /api/route/ => generated 2 bytes in 64 msecs (HTTP/1.1 200) 5 headers in 162 bytes (1 switches on core 1)
When I make the request through Postman, however, the request works totally fine and comes back with the created object in JSON, and in the logs it's recorded as a POST.
The backend is currently written in Django, using Django Rest Framework for the REST API. Here is the Route in our urls.py file:
url(r"^api/route/$", DataListView.as_view())
And I know that the DataListView works, because Postman works totally fine with it.
I've had similar problems where it wouldn't work because I was posting to a route without the slash, and that's not the case here. I know I'm posting to the route with the trailing slash, as you can see for yourselves.
QUESTION: How do I get this to work? And why would it be working in Postman, but not using the requests library?
EDIT 1:
Here's the headers in the request if that gives any clues:
{
'User-Agent': 'python-requests/2.22.0',
'Accept-Encoding': 'gzip, deflate',
'Accept': '*/*',
'Connection': 'keep-alive',
'Authorization': 'Bearer <access-token>'
}
EDIT 2:
I just did this:
print(resp.request.method)
and it printed out GET... No idea why. When I did it do my local server though, it printed out POST. Could it have something to do with the fact that I'm posting to a https:// URL? This is bizzare.
From this, it looks like maybe it's getting a 301 or 302 redirect that's causing this.
I ended up doing what #IanStapletonCordasco suggests for debugging in the question that I linked to and found out my HTTP_PROTOCOL was being set to "http" instead of "https", which would result in a proxy redirect from nginx that was changing the POST to a GET. I changed that in my config file where that variable is set, and it worked.
Something else to note, for people that are having a similar problem, look at the URL you're posting to. If you have strict trailing slash checking turned on in Django (which I'm pretty sure is on by default), and you're posting to a URL without the trailing slash, it'll come back with a 30x redirect response that will cause a similar thing to happen. Try adding the slash and it should work.
So I'm learning my way around web crawlers and automatization. I'm trying to automate the login for mega.nz without using their official API (as far as I'm concerned it's even outdated for Python).
And this one is the code (currently not working since no data is really being sent). I don't want to use a browser.
loginURL = 'https://mega.nz/login'
requestURL = 'https://mega.nz/fm/dashboard'
payload = {
'login-name2': 'test#email.com',
'login-password2': 'password',
'login-check2': ''
}
with requests.session() as s:
s.post(loginURL, headers=headers, data=payload)
r = s.get(requestURL)
print(r.text)
Headers I am using:
{'Content-Type': 'text/html', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Headers': 'MEGA-Chrome-Antileak', 'Access-Control-Max-Age': '86400', 'Content-Encoding': 'gzip', 'Content-Length': '934', 'Strict-Transport-Security': 'max-age=63072000; includeSubDomains; preload', 'X-Frame-Options': 'DENY', 'Set-Cookie': 'geoip=IT', 'Content-Security-Policy': "default-src 'self' data: blob: *.mega.co.nz *.mega.nz http://*.mega.co.nz http://*.mega.nz wss://*.karere.mega.nz *.karere.mega.nz:1380 http://127.0.0.1:6341 localhost.megasyncloopback.mega.nz:6342; script-src 'self' *.mega.co.nz *.mega.nz data: blob:; style-src 'self' 'unsafe-inline' *.mega.co.nz *.mega.nz data: blob:; frame-src 'self' mega: *.megaad.nz; img-src 'self' *.mega.co.nz *.mega.nz data: blob:", 'Connection': 'Keep-Alive'}
How can I automate signing into this?
Try this https://github.com/richardARPANET/mega.py/
It worked for me.
There is an example step by step on README.rst
You may want to read requests documentation about Authentication, it gives a few methods to authenticate through HTTP.
You can find it here.
I did not find any information about an HTTP API for Mega. Are you trying to get access to the site via the web interface that you would use in your browser? It could be very difficult or impossible to get your software working this way.
Usually you would only use plain HTTP requests when the service you try to access provides a working REST API. (see for example the Spotify API)
Maybe take a look at this example for accessing Mega from Python. This uses the official Mega C++ API which you can access from your Python script.
I am trying to retrieve the access token for the Yahoo API, using the explicit grant flow as described in this document:
https://developer.yahoo.com/oauth2/guide/flows_authcode
Everything is fine until Step 4: Exchange authorization code for Access Token
I wrote the following python script to retrieve the code:
import urllib2
import requests
import json
url = 'https://api.login.yahoo.com/oauth2/get_token'
body = "grant_type=authorization_code&redirect_uri=oob&code=************"
headers = {
'Authorization': 'Basic **************',
'Content-Type': 'application/json'
}
r = requests.post(url, data=body, headers=headers)
print r
Note: I replaced sensitive data with "****"
Now, when I execute the script, I only get the "401" error message.
I am 100% sure that the login credentials are fine, so it seems to be related to the way I make the request. It's also the first time that I am using "requests" in python.
Would be great, if you could give me some feedback on the code, and if I am passing the header and body information correctly. I am especially unsure about the passing of the body. The documentation only states the following:
Sample Request Body: grant_type=authorization_code&redirect_uri=https%3A%2F%2Fwww.example.com&code=abcdef
Change your body variable to a dict, i.e.,
body = {
'grant_type': 'authorization_code',
'redirect_uri': 'oob',
'code': '************',
}
No other changes are needed. Hope it helps.
Tough the problem already solved. But may be other user can still get the same 401 error even if they use correct dict as me. The problem is that the code generated in step 2 in the link can be only use ONCE. And this will get the same 401 error. This took me some time to figure it out. Hope this helps others.
I am trying to get my Django app (NOT using Google app engine) retrieve data from Google Contacts using Google Contacts Data API. Going through authentication documentation as well as Data API Python client docs
First step (AuthSubRequest) which is getting the single-use token works fine. The next step(AuthSubSessionToken), which is upgrade single-use token to a session token. The python API call UpgradeToSessionToken() simply didn't work for me it gave me NonAuthSubToken exception:
gd_client = gdata.contacts.service.ContactsService()
gd_client.auth_token = authsub_token
gd_client.UpgradeToSessionToken()
As an alternative I want to get it working by "manually" constructing the HTTP request:
url = 'https://www.google.com/accounts/AuthSubSessionToken'
headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'AuthSub token=' + authsub_token,
'User-Agent': 'Python/2.6.1',
'Host': 'https://www.google.com',
'Accept': 'text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2',
'Connection': 'keep-alive',
}
req = urllib2.Request(url, None, headers)
response = urllib2.urlopen(req)
this gives me a different error:
HTTP Error 302: The HTTP server returned a redirect error that would lead to an infinite loop. The last 30x error message was: Moved Temporarily
What am I doing wrong here? I'd appreciate help/advice/suggestions with either of the methods I am trying to use: Python API call (UpgradeToSessionToken) or manually constructing HTTP request with urllib2.
According to the 2.0 documentation here there is a python example set...
Running the sample code
A full working sample client, containing all the sample code shown in this document, is available in the Python client library distribution, under the directory samples/contacts/contacts_example.py.
The sample client performs several operations on contacts to demonstrate the use of the Contacts Data API.
Hopefully it will point you in the right direction.
I had a similar issue recently. Mine got fixed by setting "secure" to "true".
next = 'http://www.coolcalendarsite.com/welcome.pyc'
scope = 'http://www.google.com/calendar/feeds/'
secure = True
session = True
calendar_service = gdata.calendar.service.CalendarService()
There are four different ways to authenticate. Is it really that important for you to use AuthSub? If you can't get AuthSub to work, then consider the ClientLogin approach. I had no trouble getting that to work.