I am using OAuth within my project. but I have come into an authentication problem.
It is that I can pass the authentification mechanism of Oauth with the method "POST" but not the method "PUT". The only difference between the POST and PUT request is the method type. The body and the header is the same. The requests I used are as follows :
POST
resp, cont = client.request("http://localhost:8000/api/1.0/booking/",
"POST",
data_booking,
headers=headers)
PUT
resp, cont = client.request("http://localhost:8000/api/1.0/booking/",
"PUT",
data_booking,
headers=headers)
The client is a OAuth client.
The error message returned by server is :
Fyi : 401 Unauthorized
Similar to 403 Forbidden, but specifically for use when authentication is possible but has failed or not yet been provided
I am developing using the django framework.
The request method is as follow :
def request(self, uri, method="GET", body=None, headers=None,
redirections=httplib2.DEFAULT_MAX_REDIRECTS, connection_type=None,
callback_url=None, realm=''):
DEFAULT_CONTENT_TYPE = 'application/x-www-form-urlencoded'
if not isinstance(headers, dict):
headers = {}
is_multipart = method == 'POST' and headers.get('Content-Type',
DEFAULT_CONTENT_TYPE) != DEFAULT_CONTENT_TYPE
if body and (method == "POST" or method == 'PUT') and not is_multipart:
parameters = dict(parse_qsl(body))
if callback_url != None:
parameters['oauth_callback'] = callback_url
else:
if callback_url != None and not is_multipart:
parameters = {'oauth_callback': callback_url}
else:
parameters = None
req = Request.from_consumer_and_token(self.consumer,
token=self.token, http_method=method, http_url=uri,
parameters=parameters)
req.sign_request(self.method, self.consumer, self.token)
if method == "POST" or method == "PUT":
headers['Content-Type'] = headers.get('Content-Type',
DEFAULT_CONTENT_TYPE)
if is_multipart:
headers.update(req.to_header(realm))
else:
body = req.to_postdata()
elif method == "GET":
uri = req.to_url()
else:
headers.update(req.to_header(realm))
return httplib2.Http.request(self, uri, method=method, body=body,
headers=headers, redirections=redirections,
connection_type=connection_type)
Anyone has an idea?
Some OAuth server implementations only include form-encoded body parameters in the signature base string when the HTTP method is POST. This was the right behavior in OAuth 1.0 but was corrected in later revisions. Try making a PUT request without a body and see if that helps. If it does, you will need to ask the server library maintainer to fix this or limit your calls not to include a form-encoded body when using a put.
Related
I am trying to make request to Clash of Clan Api and after requesting the right data it returns 200 ok & if i search wrong data it returns 404 not found. How to flash message after the data is not found according to the HTTP response from the API?
my views in flask
#app.route('/player', methods=['GET', 'POST'])
def player():
headers = header
url = ('https://api.clashofclans.com/v1/players/{}')
query = request.form.get('search')
player_id = urllib.parse.quote(query)
stats = requests.get(url.format(player_id), headers=headers).json()
return render_template('player.html', stats=stats, data=stats['achievements'])
stats = requests.get(url.format(player_id), headers=headers).json()
Here, you just take the JSON from the body and discard a bunch of useful data. Instead,
response = requests.get(url.format(player_id), headers=headers)
stats = response.json()
status_code = response.status_code
success = response.ok
# ...
You can see all the things you can get from the Response object in API documentation.
I am sending the below payload to the test api as shown but am getting an empty body. Please help. I have checked and I cant see where the problem is.
import requests
#(version 2.20.1)
requests.post('http://127.0.0.1:8000/api/test/',
json={'event_ref_id': 'PZpHoGrGKbIEv', 'member_no': 'mb001', 'action': 'course_registration'},
headers={'Content-Type': 'application/json'})
My Django endpoint is very simple as shown below but an getting an empty body
#api_view(['POST'])
def get_test(request):
print(request.body)
body_unicode = request.body.decode('utf-8')
body = json.loads(body_unicode)
print(body)
return Response(status=status.HTTP_200_OK)
Why API print body is
b'{}'
{}
This is how my login method looks like:
def login():
if request.method == "GET":
return render_template('user/login.html')
else:
jwt_token = "xxxx"
resp = redirect(url_for('home.index'))
resp.headers.set('Authorization', "JWT {}".format(jwt_token))
return resp
This works fine but the Authorization header does not make it to home.index page.
How do I tell flask to preserve this header on every request?
------Edit---------
This works if I add Token to Cookie as resp.set_cookie('Authorization', "JWT {}".format(json_data["access_token"])) but I would like to keep it in the Authorization Header.
If you want to set Authorization header on all requests, you could do something like this:
#app.after_request
def after_request(response):
my_jwt_token = 'xxxx'
response.headers['Authorization'] = my_jwt_token
return response
More information on documentation: http://flask.pocoo.org/docs/1.0/api/#flask.Flask.after_request
Is there any way to make a RESTful api call from django view?
I am trying to pass header and parameters along a url from the django views. I am googling from half an hour but could not find anything interesting.
Any help would be appreciated
Yes of course there is. You could use urllib2.urlopen but I prefer requests.
import requests
def my_django_view(request):
if request.method == 'POST':
r = requests.post('https://www.somedomain.com/some/url/save', params=request.POST)
else:
r = requests.get('https://www.somedomain.com/some/url/save', params=request.GET)
if r.status_code == 200:
return HttpResponse('Yay, it worked')
return HttpResponse('Could not save data')
The requests library is a very simple API over the top of urllib3, everything you need to know about making a request using it can be found here.
Yes i am posting my source code it may help you
import requests
def my_django_view(request):
url = "https://test"
header = {
"Content-Type":"application/json",
"X-Client-Id":"6786787678f7dd8we77e787",
"X-Client-Secret":"96777676767585",
}
payload = {
"subscriptionId" :"3456745",
"planId" : "check",
"returnUrl": "https://www.linkedin.com/in/itsharshyadav/"
}
result = requests.post(url, data=json.dumps(payload), headers=header)
if result.status_code == 200:
return HttpResponse('Successful')
return HttpResponse('Something went wrong')
In case of Get API
import requests
def my_django_view(request):
url = "https://test"
header = {
"Content-Type":"application/json",
"X-Client-Id":"6786787678f7dd8we77e787",
"X-Client-Secret":"96777676767585",
}
result = requests.get(url,headers=header)
if result.status_code == 200:
return HttpResponse('Successful')
return HttpResponse('Something went wrong')
## POST Data To Django Server using python script ##
def sendDataToServer(server_url, people_count,store_id, brand_id, time_slot, footfall_time):
try:
result = requests.post(url="url", data={"people_count": people_count, "store_id": store_id, "brand_id": brand_id,"time_slot": time_slot, "footfall_time": footfall_time})
print(result)
lJsonResult = result.json()
if lJsonResult['ResponseCode'] == 200:
print("Data Send")
info("Data Sent to the server successfully: ")
except Exception as e:
print("Failed to send json to server....", e)
I am trying to take some working code and change from urlib2 to requests.
The original code provides basic login information of username, password and posts the KEY and SECRET in the header of the urllib2 request. The following code is my attempt to change to using the requests module and gain some functionality for making additional API calls. I have tried dozens of combinations and all return a code 400. Apparently, my requests code does not successfully furnish the needed information to return a 200 response and provide the needed authorization token.
## Import needed modules
import urllib2, urllib, base64
import httplib
import requests
import json
## initialize variables
KEY = "7f1xxxx-3xxx-4xxx-9a7f-8be66839dede"
SECRET = "45xxxxxx-45xxx-469a-9ae9-a7927a76cfeb"
userName = "my-email#xxx.com"
passWord = "mypassword"
URL = "https://company.com/auth/token"
token = None
sessionid = None
DATA = urllib.urlencode({"grant_type":"password",
"username":userName,
"password":passWord})
base64string = base64.encodestring('%s:%s' % (KEY, SECRET)).replace('\n', '')
request = urllib2.Request(URL, DATA)
request.add_header("Authorization", "Basic %s" % base64string)
result = urllib2.urlopen(request)
token = result.read()
print token
This returns my authorization token and all is well. I can pass the token to the authorization server and have full access to the api for interacting with the database. Below is the attempt to use requests and have the added functions it provides.
client = requests.session()
payload = {"grant_type":"password",
"username":userName,
"password":passWord,
"applicationId": KEY
}
headers = {'content-type':'application/json',
"grant_type":"password",
"username":userName,
"password":passWord,
'applicationsId': KEY,
'Authorization': base64string,
'token': token,
'sessionid': sessionid
}
response = client.post(URL, params = payload, headers=headers)
token = response.content
print token
{"error":"invalid_request"}
print response
<Response [400]>
If you want to use basic auth you should use the method from requests..
Your post should look like
response = client.post(
URL,
params = payload,
headers=headers,
auth=HTTPBasicAuth(
KEY,
SECRET
))
Somewhere in a post a contributor to another question mentioned some items actually needed to be in the body of the request not in the header. I tried various combos and the following solved the 400 response and accomplished my goals.
data = {"grant_type":"password",
"username":userName,
"password":passWord,
"applicationId": KEY
}
headers = {'Authorization': "Basic %s" % base64string,
'token': token
}
response = client.post(URL, data = data, headers=headers)
token = response.text
print token