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.
Related
I'm trying to access the Letterboxd api to get an authentification token but I keep getting Bad Request feedback. Here's my code:
import requests
import urllib
import json
headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': 'application/json'
}
url = 'https://api.letterboxd.com/api/v0/auth/token'
body = {
'grant_type': 'password',
'username': 'myname',
'password': 'mypassword'
}
response = requests.post(
url+urllib.parse.urlencode(headers), data=json.dumps(body))
print('\n')
print(response.text)
Any idea what I did wrong? The response is just an HTTP document with no info besides the Error message "400 Bad Request". Heres the documentation if it helps https://api-docs.letterboxd.com/#auth
First: I can't test if all code works.
You send headers in url but you should send it as part of headers=.
And when you use module requests then you can use json=body instead of data=json.dumps(body)
response = requests.post(url, headers=headers, json=body)
But header 'Content-Type': 'application/x-www-form-urlencoded' suggests that you will send data as form data, not json data - which needs data=body without converting to json
response = requests.post(url, headers=headers, data=body)
EDIT:
In your link to documentation I see link to python module (in part "Example implementations") - so maybe you should use it instead of writing own code because documentation mentionts something about "All API requests must be signed" (in part "Request signing") - and this may need extra code to create it.
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 a Python user, beginner level. I'm trying to follow this instruction on Basecamp 3. Documentation: https://github.com/basecamp/bc3-api
I've successfully gone through the authorization step and was able to retrieve the access token (which consists of 3 keys: access_token, expires_in and refresh_token.
Now i'm trying to pull some actual data from Basecamp, and the most basic call is to https://3.basecampapi.com/999999999/projects.json (with 99999999 being my account number, which I have).
The instruction has an example in curl: curl -H "Authorization: Bearer $ACCESS_TOKEN" -H 'User-Agent: MyApp (yourname#example.com)' https://3.basecampapi.com/999999999/projects.json
But I cannot translate this to Python. I tried many methods of passing the keys to the header call but none works. Can anyone help me out?
Code:
url = "3.basecampapi.com/99999999/projects.json"
headers = {'Content-Type': 'application/json',
'User-Agent': 'MyApp (myemail#gmail.com)',
'access_token': 'Access_Token_String',
'expires_in': '1209600',
'refresh_token': 'Refresh_token_string'}
result = requests.post(url, headers=headers)
This is an old question, but posting an answer for anyone who happens to stumble upon this.
url = f'3.basecampapi.com/{PROJECT_ID}/projects.json'
headers = {'User-Agent': 'MyApp (myemail#gmail.com)',
'Content-Type': 'application/json; charset=utf-8',
'Authorization': f'Bearer {ACCESS_TOKEN}'
response = requests.get(url, headers=headers)
Then view the output via response.json()
I am trying to make REST Call for azure using python,
Have created Access token using ADAL in python.
But getting Error called "provided Authorization header is in invalid format."
Here is the code for that:
import adal
import requests
token_response = adal.acquire_token_with_username_password(
'https://login.windows.net/abcd.onmicrosoft.com',
'user-name',
'password'
)
access_token = token_response.get('accessToken')
url = 'https://management.azure.com/subscriptions/{subscription- id}/providers/Microsoft.Network/virtualnetworks?api-version=2015-06-15'
headers = {'Content-Type': 'application/json',
'Authorization': access_token}
response = requests.get(url=url,headers = headers)
print(response.status_code)
print(response.text)
Can anyone tell me how the access-token should look like?
And is this the correct way to generate token for REST in python?
I am reffering this link for above code:
https://msdn.microsoft.com/en-us/library/azure/mt163557.aspx
As #GauravMantri said, the format of the value of the header Authorization is Bearer <access-token> that you can refer to the section Calling ARM REST APIs of the doc "Resource Manager REST APIs".
For example in the section above.
GET /subscriptions/SUBSCRIPTION_ID/resourcegroups?api-version=2015-01-01 HTTP/1.1
Host: management.azure.com
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json
You would need to prepend Bearer to your token. Something like:
headers = {'Content-Type': 'application/json',
'Authorization': 'Bearer ' + access_token}
I am trying to mimic a user action on a site programmatically using Python requests API.
to accomplish this programmatically the request must have user/pass authentication and also should pass few NVPs as Cookies in Header.
To get the NVPs I initially make a dummy request and the server returns me the cookies.
I acquire the required values from these cookies and use this to send the actual request.
But the request doesn't succeeds and server complains I am not logged in.
But if I use the cookie value from my browser the request succeeds.
The the dummy request to programmatically acquire JSESSIONID,glide_user and glide_user_session params in cookie is
response = requests.get('http://example.com/make_dummy_get',auth=('username','pasword'))
cookie_params = response.cookies.items()
below is the actual request
headers = {
'Host': 'example.com'
,'Connection': 'keep-alive'
,'Content-Length': 113
,'Cache-Control': 'max-age=0'
,'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8'
,'Origin': 'example.com'
,'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36'
,'Content-Type': 'application/x-www-form-urlencoded'
,'Referer': 'www.example.com/asdas/'
,'Accept-Encoding': 'gzip,deflate,sdch'
,'Accept-Language': 'en-US,en;q=0.8'
,'Cookie': 'JSESSIONID=B6F7371A11825472CAB0366A4DCDD8EFB; glide_user="SC:Z3Vlc3Q=:b890b38b7f000001121dbe81a08c413ca5"; glide_user_session="SC:Z3Vlc3Q=:b890b38b7f000001121dbe81a08c413ca5"'
}
form_data = {
'param1': 'value1'
,'param2': 'value2'
,'param3': 'value3'
}
res = requests.post('http://example.com/make_post_request',auth=('username','pasword'),data=form_data,headers = headers)
It seems to me that the session created by my dummy request for some reason is getting closed
and Hence the second request is rejected and html response says I must login to access the requested resource.
I did the same exercise with Java apache's HttpClient and ended with the same issue.What am I missing here to make the request succeed without any login or authentication issues?
First you should be using a Session object from requests. This will manage cookies (and prepare them for you) so you do not have to create the cookie header for yourself.
s = requests.Session()
s.get('http://example.com/make_dummy_get',auth=('username','pasword'))
print(s.cookies)
Next I have to strongly advise you to stop setting the following headers:
Host
Content-Length
Content-Type
Cookie
All four of those headers will be generated by requests for you. The Cookie header will be generated using the CookieJar that the Session uses. The Content-Length and Content-Type will be computed while requests prepares the body.
Also, if you're trying to use cookies to authenticate, the server is likely becoming confused because you're also passing auth=('username', 'password') in your second request. That's generating an authorization header so you're both sending a Cookie header and an Authorization header. The server sees this as suspicious most likely and rightly refuses to accept your request as authenicated.