how can i invalidate a bearer token from twitter with rauth?(https://dev.twitter.com/docs/api/1.1/post/oauth2/invalidate_token)
I tried to do it via a oauth2 session but it doesn't work.
By the way, is there a way to see the complete request which will be send/which is created by rauth? This could be very helpful for debugging and to understand what rauth produces.
Here is my code so far:
session = rauth.OAuth2Session(client_id=c_key,
client_secret=c_secret,
access_token=o_bearer_token)
bearer_raw = session.post('https://api.twitter.com/oauth2/invalidate_token',
params={ 'Host': 'api.twitter.com',
'User-Agent': '',
'Accept': '*/*',
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': str(len(o_bearer_token)),
'access_token':str(o_bearer_token)})
I think the request is being formatted improperly. It looks like the Twitter docs are indicating that it should be something like this:
session = rauth.OAuth2Session(client_id=KEY,
client_secret=SECRET,
access_token=TOKEN)
r = session.post('https://api.twitter.com/oauth2/invalidate_token', bearer_auth=True)
By the way, Rauth is Requests; it's just a layer on top of Requests. So yes, you can see a request as you would with Requests. Something like r.request should expose what you're looking for.
Related
I need to send a PUT request with authentication in one time.
When I use Postman for that and input
headers = {'Authorization': 'Basic Token', 'Content-Type': 'application/json'}
Authorization = Basic Auth Username = 'login' Password = 'pass'
Body = data
everything goes well.
If I try to write request in python:
req = r.put(url, headers={'Authorization': 'Basic Token', 'Content-Type': 'application/json'}, auth=HTTPBasicAuth('login','password'), data=data)
I get response 400 Bad Request
Whats wrong with my request?
I don't know if this works for your case, but I did use Basic authentication a while ago to authenticate with the Reddit API.
Here's my code:
import requests
client_auth = requests.auth.HTTPBasicAuth("put something here","put something here")
headers = {"User-Agent": "manage your reddit easily by u/0xff"}
code = "ajkldjfalkdjflajfd;lakdjfa"
data = {
"code":code,
"grant_type":"authorization_code",
"redirect_uri":"http://127.0.0.1:3000/authorize_callback"
}
r = requests.post("https://www.reddit.com/api/v1/access_token", auth=client_auth, data=data, headers=headers);
print(r.content)
Just make the appropriate changes for your case and try it.
You are setting authorization information twice, and different HTTP libraries will handle this conflict in different ways.
HTTP Basic Authorization uses the Authorization header, encoding the username and password (separated by :) as base64 and setting the header to the value Basic plus space plus the base64 encoded string. You are telling both POSTman and requests to set the Authorization header to the string Basic Token and to use a username and password for Basic Auth, so the clients will have to make a choice between these two options.
Trying this out in requests version 2.25.1 I see that the auth information will win here:
>>> from requests import Session, Request
>>> from requests.auth import HTTPBasicAuth
>>> req = Request(
... "PUT",
... "http://example.com",
... headers={
... 'Authorization': 'Basic Token',
... 'Content-Type': 'application/json'
... },
... auth=HTTPBasicAuth('login','password'),
... data=b"{}"
... )
>>> session = Session()
>>> prepped = session.prepare_request(req)
>>> from pprint import pp
>>> pp(dict(prepped.headers))
{'User-Agent': 'python-requests/2.25.1',
'Accept-Encoding': 'gzip, deflate',
'Accept': '*/*',
'Connection': 'keep-alive',
'Authorization': 'Basic bG9naW46cGFzc3dvcmQ=',
'Content-Type': 'application/json',
'Content-Length': '2'}
The above session creates a prepared request so I can inspect the effect of the auth argument on the headers given to the request, and as you can see the Authorization header has been set to a base64 value created from the login and password pair.
It looks like Postman will do the same, the UI even tells you so:
You didn't share any details about what web service you are using or what expectations that service has for headers or request contents. If this a OAuth2-protected service, then you should not confuse obtaining a token with using that token for subsequent requests to protected URLs. For a grant_type="password" token request, it could be that the server expects you to use the username and password in a Basic Auth header, but it may also expect you to use client_id and client_secret values for that purpose and put the username and password in the POST body. You'll need to carefully read the documentation.
Other than that, you could replace your destination URL with an online HTTP echo service such as httpbin. The URL https://httpbin.org/put will give you a JSON response with the headers that the service received as well as the body of your request.
Further things you probably should be aware of:
requests can encode JSON data for you if you use the json argument, and if you do, the Content-Type header is generated for you.
You don't need to import the HTTPBasicAuth object, as auth=(username, password) (as a tuple) works too.
I am trying to get information out of REST API with Python and it requires OAuth identification. I've managed to compose the request with Postman and it works. However the python code that Postman gives me doesn't work:
import requests
url = "https://www.somewebsite.com/api/rest/products/store/2"
querystring = {"limit":"100","page":"5"}
headers = {
'Authorization': "OAuth oauth_consumer_key="3626311748bcf2072da2bd475fccfa3c",\
oauth_token="878c7c0eb6122e6208b75e2ba9e23f86",\
oauth_signature_method="HMAC-SHA1",oauth_timestamp="1560892926",\
oauth_nonce="9Cy9wmOo21v",oauth_signature="9VqTR2qFQLZ%2Fz2Ibvny1e%2BC7Zes%3D"",
'User-Agent': "PostmanRuntime/7.15.0",
'Accept': "*/*",
'Cache-Control': "no-cache",
'Postman-Token': "eef345cc-52ee-4496-8109-e7ea013adb9c,0834423c-041c-4ca5-8bef-33876c311ef6",
'Host': "www.inart.com",
'cookie': "PHPSESSID=gmjmllng429gfk8t0hvd1abbu3",
'accept-encoding': "gzip, deflate",
'Connection': "keep-alive",
'cache-control': "no-cache"
}
response = requests.request("GET", url, headers=headers, params=querystring)
print(response.text)
The not working part is actually the nonce, the timestamp and the signature of course. I've made a function that generates a random nonce and a random timestamp but I have no idea how to generate a valid signature for HMAC-SHA1.
Is there a library that would do the authentication for me or do I need to write my own function to generate the valid signature ? Does the signature depend on the whole call or just parts like the nonce and timestamp and tokens ?
Any help would be appreciated!
You can check this library
https://requests-oauthlib.readthedocs.io/en/latest/.
It has both Oauth1 and Oauth2 support with great documentation. No need to concern about creating nonce, timestamp as well as oauth_signature. Just provide your app_key, app_secret, request_token_url, authorization_url and access_token_url.
You can use this approach to use both oauth2 Libary and Request, I will prefer to use ouath2 with Authorization: Bearer Token.
However, OAuth 1.0 required crypto-implementation and crypto-interoperability. While secure, it was a challenge for many developers to implement.
Where OAuth 2.0 defines four roles, (client, authorization server, resource server, and resource owner,) OAuth 1 uses a different set of terms for these roles. The OAuth 2.0 “client” is known as the “consumer,” the “resource owner” is known simply as the “user,” and the “resource server” is known as the “service provider”. OAuth 1 also does not explicitly separate the roles of resource server and authorization server.
params = {
"oauth_version": "1.0",
"oauth_nonce": oauth2.generate_nonce(),
"oauth_timestamp": str(oauth2.generate_timestamp()),
"oauth_token": token.key,
"oauth_consumer_key": consumer.key
}
req = oauth2.Request(method="GET", url=url, parameters=params)
signature_method = oauth2.SignatureMethod_HMAC_SHA1()
req.sign_request(signature_method, consumer, token)
headers = req.to_header()
payload = {}
response = requests.request("GET", url, headers=headers, data=payload)
print(response.text)
I'm trying to create a VM using the python client. The call I'm making is
import googleapiclient.discovery
compute = googleapiclient.discovery.build('compute', 'v1')
compute.instances().insert(
project='my-project',
zone='us-central1-c',
body=config).execute()
(config is a json string, available here)
and the response is
<HttpError 400 when requesting https://www.googleapis.com/compute/v1/projects/my-project/zones/us-central1-c/instances?alt=json
returned "Required field 'resource' not specified">
From this forum post and this stackexchange question, it appears the problem is with the REST API headers. However headers aren't exposed the python client, as far as I know.
Is this a bug or is there something else I might be doing incorrectly?
EDIT
Following the error back to googleapiclient.http.HttpRequest, it looks like the HttpRequest object generated by build() has headers
{ 'accept': 'application/json',
'accept-encoding': 'gzip, deflate',
'content-length': '2299',
'content-type': 'application/json',
'user-agent': 'google-api-python-client/1.7.7 (gzip)' }
I tried adding 'resource': 'none' to the headers and received the same response.
After looking at this for a while, I suspect the REST API is expecting a Compute Engine resource to be specified. However, searching for the word "resource" on the official docs yields 546 results.
EDIT2
Created GitHub Issue.
Use the request body(requestBody)" instead of resources.
I am dealing with this little error but I can not get the solution. I authenticate into a page and I had opened the "inspect/network" chrome tool to see what web service is called and how. I found out this is used:
I have censored sensitive data releated to the site. So, I have to do this same request using python, but I am always getting error 500 and the log on the server side is not showing helpful information (only java traceback).
This is the code of the request
response = requests.post(url,data = 'username=XXXXX&password=XXXXXXX')
URL has the same string that you see in the image under "General/Request URL" label.
Data has the same string that you see in the image under "Form Data".
It looks very simple request but I can not get it to work :( .
Best regards
If you want your request appears like coming from Chrome, other than sending correct data you need to specify headers as well. The reason you got 500 error is probably there're certain settings on your server side disallowing traffic from "non-browsers".
So in your case, you need to add headers:
headers = {'Accept': 'application/json, text/plain, */*',
'Accept-Encoding': gzip, deflate,
...... # more
'User-Agent': 'Mozilla/5.0 XXXXX...' # this line tells the server what browser/agent is used for this request
}
response = requests.post(url,data = 'username=XXXXX&password=XXXXXXX', headers=headers)
P.S. If you are curious, default headers from requests are:
>>> import requests
>>> session = requests.Session()
>>> session.headers
{'Connection': 'keep-alive', 'Accept-Encoding': 'gzip, deflate',
'Accept': '*/*', 'User-Agent': 'python-requests/2.13.0'}
As you can see the default User-Agent is python-requests/2.13.0, and some websites do block such traffic.
I am calling google's pubsubhubbub publisher at http://pubsubhubbub.appspot.com via Django's view. I want to fetch all the youtube uploads feeds using it. I am sending a 'post' request to it using urllib2.Request, and I get 409 conflict error. I have properly setup callback url, and if I try to post the same request using: python manage shell it works perfectly fine. I am using nginx server as a proxy to gunicorn instance at the production server. What could possibly be wrong. Thanks in advance.
>>> response.request
<PreparedRequest [POST]>
>>> response.request.headers
{'Content-Length': u'303', 'Content-Type': 'application/x-www-form-urlencoded', 'Accept-Encoding': 'gzip, deflate, compress', 'Accept': '*/*', 'User-Agent': 'python-requests/1.2.0 CPython/2.6.6 Linux/2.6.18-308.8.2.el5.028stab101.3'}
>>> response.request.body
'hub.verify=sync&hub.topic=http%3A%2F%2Fgdata.youtube.com%2Ffeeds%2Fapi%2Fusers%2FUCVcFOpBmJqkQ4v6Bh6l1UuQ%2Fuploads%3Fv%3D2&hub.lease_seconds=2592000&hub.callback=http%3A%2F%2Fhypedsound.cloudshuffle.com%2Fhub%2F19%2F&hub.mode=subscribe&hub.verify_token=subscribe7367add7b116969a44e0489ad9da45ca8aea4605'
Request body, headers are same for both requests generated.
Here is the nginx config file:
http://dpaste.org/bOwHO/
It turns out I was using TransactionMiddleware which does not commit to db when model.save() is called, which was creating the issue.