I have a client id and client secret and am attempting to generate an auth token by following Sitescout's api docs. I'm using python module Requests and am getting a 400 status code back, aka malformed request, but I can't seem to figure out why.
My code:
import requests
url = "https://api.sitescout.com/oauth/token"
headers = {
"Host": "api.sitescout.com",
"Authorization": "Basic YmVldGhvdmVuOmxldG1laW4=",
"Content-Type": "application/x-www-form-urlencoded",
"Accept": "application/json",
"Content-Length": "41"
}
# Do the HTTP request
response = requests.post(url, headers=headers)
response.status_code
That is the fake base64 Authorization header provided in the docs so this snippet returns a 401 error, aka unauthorized (I have my own auth of course).
Can anyone tell me what's wrong with this?
It has been resolved. I did not put grant_type=client_credentials which, when added, returns a 200.
The docs say "Optionally, you can add form parameter scope to indicate which scopes you are requesting access to; the scope values must be space delimited (e.g., STATS AUDIENCES)." But it is the "&scope=STATS" param that is optional, not all params. The example confused me.
Now my code reads
...
params = { "grant_type" : "client_credentials" }
response = requests.post(url, headers=headers, params=params)
...
which works.
Related
I was able to get the auth token from the login api but I am trying to use it to query the events api and I am getting a 401 Client Error: Unauthorized for url error message. Here is a snippet of my code:
def action():
data = {
'login': 'xxxxxxxxx',
'password': 'xxxxx',
}
urllib3.disable_warnings()
try:
timestamp = int(round(time.time() * 1000))
print(timestamp)
r = requests.post(
'https://host:port/www/core-service/rest/LoginService/login', data=data, verify=False)
login_request = untangle.parse(r.text)
user_session_id = login_request.ns3_loginResponse.ns3_return.cdata
print(user_session_id)
response = requests.post(
'https://host:port/detect-api/rest/v1/events/retrieve',
headers={
"Accept": "application/json",
"Authorization": user_session_id,
"Content-Type": "application/json"
},
data={
"ids": 79745681,
"startTime": timestamp,
"endTime": timestamp
},
verify=False)
print(response)
res = untangle.parse(response.text)
print(res)
Can somebody please point out what is wrong with my code?
You didn't add link to API so I only guess what can make problem.
If you set "Content-Type": "application/json" then it can means you want to send json data.
So you should use
post(..., json=...)
instead of
post(..., data=...).
Using data= you send it as form, not json. And header Content-Type can't change it.
And when you use json= then you don't have to add "Content-Type": "application/json" because requests will add it automatically.
EDIT:
In comment you said that you have working curl command (but you didn't said it in question, and you didn't show curl in question)
On page https://curl.trillworks.com you can convert curl to Python (and few other languages) and mostly it works correctly.
BTW:
If you use postman for tests then it has also function to generate code for curl, Python and many other languages.
You didn't show link to API documentation but often API documentation has examples for curl and sometimes even for Python.
Below bash script works and returns a token.
curl -X POST --user <id>:<key> 'https://<name>.auth.eu-west-1.amazoncognito.com/oauth2/token?grant_type=client_credentials' -H 'Content-Type: application/x-www-form-urlencoded'
I would now like to generate a token via a Python script. I currently struggle with using requests library, but without success. Below generates Response 400 (bad request).
import requests
parameters = {"user":"<id>:<key>", "Content-Type": "application/x-www-form-urlencoded"}
response = requests.get("https://<name>.auth.eu-west-1.amazoncognito.com/oauth2/token?grant_type=client_credentials", params=parameters)
print(response)
To fix your usage of requests:
Use post() instead of get().
Use an auth object to construct a basic auth header. (Or send credentials in the body)
Remove the content type header; requests will set this for you.
Take the grant_type out of the query string. This belongs in the request body.
While the documentation for the /oauth2/token endpoint says you need to send a basic auth header for client_credentials grant, it also works if you send the client id and secret in the request body (with no auth header).
As such, these python examples both work, and are essentially equivalent:
Credentials in request body:
import requests
url = 'https://<COGNITO_DOMAIN>.auth.<REGION>.amazoncognito.com/oauth2/token'
params = {
"client_secret": "1ixxxxxxxxxxxxxxxxc2b",
"grant_type": "client_credentials",
"client_id": "7xxxxxxxxxxxxxxxt"
}
response = requests.post(url, data=params)
print(response)
print(response.text)
Credentials in basic auth header:
import requests
url = 'https://<COGNITO_DOMAIN>.auth.<REGION>.amazoncognito.com/oauth2/token'
params = {
"grant_type": "client_credentials"
}
auth = ('7xxxxxxxxxxt', '1ixxxxxxxxxxxxxxxc2b')
r = requests.post(url, data=params, auth=auth)
print(r)
print(r.text)
I'm having a problem sending an authorization token with Bearer to an API via python requests.post:
token = "eyJhbGciOiJSUzI1NiIsImtpZCI6IjZjNGE5NDBjNWE5ODE5MGJlNzIwYjI0ZDY2MTMzZWVmIiwidHlwIjoiSldUIn0.eyJuYmYiOjE1NzY4MjU0NzgsImV4cCI6MTU3NjgyOTA3OCwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo0MDQwIiwiYXVkIjpbImh0dHA6Ly9sb2NhbGhvc3Q6NDA0MC9yZXNvdXJjZXMiLCJwYXJjZWxfc3RvcmFnZSJdLCJjbGllbnRfaWQiOiJwcy5tLmNsaWVudCIsInN1YiI6ImI0ZjVmNmVjLWEyMDItNDhjZC1hZmVjLTA4ZDc3OGJmNzYzNyIsImF1dGhfdGltZSI6MTU3NjgyNTQ3OCwiaWRwIjoibG9jYWwiLCJ1c2VybmFtZSI6InZlc3RhIiwic2NvcGUiOlsib3BlbmlkIiwicHJvZmlsZSIsInBhcmNlbF9zdG9yYWdlIiwib2ZmbGluZV9hY2Nlc3MiXSwiYW1yIjpbInB3ZCJdfQ.araPfT_HS0iMXUWS0KcSq3fvowJpu9ONtNsENUtZuk7lV3vxSpyNhUULdZSFdQdZs5830afxRC9qapzYNzDI48ALDrlconKDwReaG9QQhJ61p9dTbSskJDTReGDYwRxEgmZBhjOFD_KeVklbKWevXTGQ2dW3nzGtJ26uMFrSpOww4yNBvJ9Daafson-tZNXeG6xZ09H5GHY43Qp9P25kNRBfeFyKzYuF7xoygk_TQSlMike2Fzjec9TBbudSsTP62qIAXkYckvGF5fI5buJWsw5tvrDtgKVSfVs_SD27-3MIjde27fG89sH-CUYryroy6YiHyTx6UOYTvC2dBNzm5A"
test_url = 'https://fpt.titec.ir/api/v1/parcel/getprecode'
header = {
"Authorization": "Bearer {}".format(token),
"Content-Type": "application/json",
}
data = {'serviceTypeId': '2'}
response = requests.post(test_url, data=data, headers=header)
But every time the response returned 401 status code.
In postman it works well but in python code it doesn't work. Is it a bug in requests.post?
By the way the token expires in 60 min.
Is there anyone who could help me please?
I can do this successfully with requests.get for another url that needs exactly the same token!!
I am trying to issue a POST request including local-file upload with python.
I looked up a lot of similar requests here, but none worked for me or none was specific enough to help me out.
With Postman everything works as expected and without any hickups.
But representing the very same with python I am not able to achieve it.
I tried various combinations of params-, body- and file-dictionaries, without success
This is how the working postman request body looks like:
This is how the params of this postman request have been configured:
This is my python code
metadata = {
"name":"MyFile" ,
"type":"myFileType" ,
"parentId":"1cc58622-3bc0-4fc4-a222-a64bd8d90af1"
}
fileForUpload = {'upload_file': open("/home/myuser/blablabla/testfile.jpg)", "rb")}
params = {"metadata":json.dumps(metadata), "file": "filename"}
headers = {
"content-type": "application/json",
"Authorization": 'Bearer ' + token,
"accept-encoding": "gzip, deflate"
}
response = requests.post(url, headers = headers, params = params, files = fileForUpload)
I receive an error message of the API-endpoint, claiming that the file parameter is missing ...
Any idea what I am doing wrong?
I am trying to call the shiftplanning API with the following code:
import requests
url= "https://humanity.com/api/"
payload = {"key": "keyvalue", "request": { "module": "staff.login", "method": "GET","username": "myusername", "password": "mypassword"}}"
headers = {
'content-type': "application/x-www-form-urlencoded",
'cache-control': "no-cache",
}
r = requests.post(url, data = payload
, headers= headers)
r.text
I used Postman to test the api beforehand and it worked fine. The payload in the Postman code creator, however, looks like this:
payload = "data={\r\n \"key\": \"keyvalue\",\r\n \"request\": {\r\n \"module\": \"staff.login\",\r\n \"method\": \"GET\",\r\n \"username\": \"myusername\",\r\n \"password\": \mypassword\"\r\n }\r\n}"
I assume, that the payload variable actually needs to be formatted as a string, as the doc at shiftplanning api says:
Remember that any data passed to the API is to be formatted as JSON, and its string value needs to be sent via the POST HTTP request method all as the post variable 'data' (Checkout the 9th line from an example below). Also Content-Type needs to be set to application/x-www-form-urlencoded.
However, no matter what I do, I always get the html of the api as a return, not the json response to my http request.
Using
r.json()
doesn't do anything, except raising an error, due to the returned html.
I also tried using
json = payload
in the post request, that didn't change anything either.`
Any help and explanation is appreciated. I'd really like to understand what I am doing wrong, as it seems to be pretty straightforward to execute.
Change content-type in headers to application/json if you want json response. Postman automatically sets that header for you but you need to set it in your Python code.