I simply cannot get this to work.
header = {"Content-Type": "application/json; charset=utf8"}
params = {"api_dev_key": dev_key, "api_user_name": username, "api_user_password": password}
req = requests.post("http://pastebin.com/api/api_login.php", params = json.dumps(params), headers = header)
print(req.status_code, req.reason, req.text)
The variables (my credentials) are just strings.
The response I get:
(200, 'OK', u'Bad API request, invalid api_dev_key')
There's nothing wrong with the key, this POST works fine when I use https://www.hurl.it
You need to just use data=params:
req = requests.post("http://pastebin.com/api/api_login.php", data=params)
Related
I have the following request being sent in React Native:
const getData = async (cookie) => {
const resp = await fetch('/some_info');
const data = await resp.json();
console.log(data)
}
as you can see I purposefully did not add the appropriate header:
headers: {
'X-CSRF-TOKEN':value,
}
in the request because I wanted to verify that the GET request would fail without it.
The following are my configs:
JWT_ACCESS_TOKEN_EXPIRY_MINS = 15
JWT_REFRESH_TOKEN_EXPIRY_MINS = 1000
JWT_TOKEN_LOCATION = ['cookies']
JWT_COOKIE_CSRF_PROTECT = True
JWT_COOKIE_SECURE = False # change to True in prod
And in my browser I can see the following relevant cookies:
The endpoint is defined as follows:
#app.route('/some_info', methods=['GET'])
#jwt_required
def get_some_info():
user_identity = get_jwt_identity()
name = get_user_name_from_identity()
age = get_user_age_from_identity()
return jsonify({
'name': name,
'age': age
})
When the request happens, in the console log, I get a 200 and am able to see the json data. In the Request Headers (Using Chrome Inspector) I see that the X-CSRF-TOKEN is never set. Why is this happening/ why is the request going through ?
From JWT Extended Documentation:
# By default, the CRSF cookies will be called csrf_access_token and
# csrf_refresh_token, and in protected endpoints we will look for the
# CSRF token in the 'X-CSRF-TOKEN' header. You can modify all of these
# with various app.config options. Check the options page for details.
The answer is in the documentation. CSRF protection only happen on methods that can mutate data, aka not GET
Here is the documentation:
JWT_CSRF_METHODS
The request types that will use CSRF protection. Defaults to ['POST', 'PUT', 'PATCH', 'DELETE']
You can test that it works by adding GET to the list or calling a POST-type endpoint
I am sending a PATCH request to my DRF server in Postman and it works perfect
However when I do the same in Python I get:
<Response [405]> http://127.0.0.1:8000/api/title/8174/
b'{"detail":"Method \\"PATCH\\" not allowed."}'
Method Not Allowed
My function that sends data:
ss_token = os.getenv('SS_TOKEN')
headers = {
'Authorization': 'Token ' + ss_token,
}
source = Source.objects.all().first()
url = source.url + str(self.ss_id) + '/'
response = requests.patch(source.url, headers=headers, data={'key':'value'})
print(response, url)
print(response.content)
print(response.reason)
return True
Do I have to send other headers to the API to make the PATCH work?
Ah looks like I made a mistake. Forgot to replace source.url with the new url variable called 'url' variable. Because that add the 'ss_id' at the url' so it becomes 'api/title/ID/' instead of just 'api/title'
url = source.url + str(self.ss_id) + '/'
response = requests.patch(url, headers=headers, data={'key':'value'})
I am building both an iOS client and a django backend service. The connection made between the systems is OAUTH2, implemented by the django-oauth2-toolkit.
Although the following command done in curl works (returns an access token):
curl -X POST -d "grant_type=password&username=<user>&password=<password>" http://<clientID>:<clientSecret>#localhost:8000/o/token/
The following Swift snippet, that uses Alamofire, receives "invalid_client", as a response.
let request = "http://\(Authentication.clientId):\(Authentication.clientSecret)#localhost:8000/o/token/"
var URLRequest = NSMutableURLRequest(URL: NSURL(string: request)!)
URLRequest.HTTPMethod = "POST"
let parameters = ["grant_type": "password", "username": in_username.text!, "password": in_password.text!]
let encoding = Alamofire.ParameterEncoding.URL
(URLRequest, _) = encoding.encode(URLRequest, parameters: parameters)
URLRequest.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
Alamofire.request(URLRequest)
.responseJSON { response in
let data = response
print(data)
}
I then traced the InvalidClientError in the django-oauth2-toolkit source, and found that the exception was raised in the highlighted snippet of the following file:
oauthlib/oauth2/rfc6749/grant_types/resource_owner_password_credentials.py
if self.request_validator.client_authentication_required(request):
log.debug('Authenticating client, %r.', request)
print(request) # I included this print message to inspect the request variable in console.
if not self.request_validator.authenticate_client(request):
log.debug('Client authentication failed, %r.', request)
raise errors.InvalidClientError(request=request) # RAISED!
I included the print(request) line to inspect the differences between the request made by curl and by Alamofire. The major difference was that the curl version included an authorization key:
'Authorization': 'Basic Z3ZFSjVXejloUGgybUJmdDNRaGhXZnlhNHpETG5KY3V6djJldWMwcjpSbVNPMkpwRFQ4bHp1UVFDYXN3T3dvVFkzRTBia01YWWxHVHNMcG5JUGZCUHFjbHJSZE5EOXQzd3RCS2xwR09MNWs1bEE4S2hmRUkydEhvWmx3ZVRKZkFXUDM4OERZa1NTZ0RvS0p3WjUyejRSQ29WRkZBS01RS1lydEpsTWNXag=='
and the Alamofire request didn't.
I highly suspect this is the culprit, but I really don't know else to do though from here on. I would really appreciate any wisdom.
Found the answer!
Was reading through a RFC document on the HTTP protocol, when this section caught my eye.
https://www.rfc-editor.org/rfc/rfc1945#section-11.1
Specifically,
To receive authorization, the client sends the user-ID and password,
separated by a single colon (":") character, within a base64 [5]
encoded string in the credentials.
It seems that Alamofire does not encode in 64 bits the clientId and clientSecret, as expected. Obviously, curl does this automatically. So I did the following:
First encode:
static let clientData: NSData = "\(clientId):\(clientSecret)".dataUsingEncoding(NSUTF8StringEncoding)!
static let client64String = clientData.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.init(rawValue: 0))
Then set the request header using the resulting value:
let request = "http://localhost:8000/o/token/"
var URLRequest = NSMutableURLRequest(URL: NSURL(string: request)!)
URLRequest.HTTPMethod = "POST"
let parameters = ["grant_type": "password",
"username": in_username.text!,
"password": in_password.text!,
]
let encoding = Alamofire.ParameterEncoding.URL
(URLRequest, _) = encoding.encode(URLRequest, parameters: parameters)
// SOLUTION!
URLRequest.setValue("Basic \(Authentication.client64String)", forHTTPHeaderField: "Authorization")
Alamofire.request(URLRequest)
.responseJSON { response in
let data = response
print(data)
}
I then received the expected token as a response.
Is it not possible to batch query the graph using 'method/fql.query?query=...' using multiple access tokens?
I have never had trouble in the past batch querying non-fql endpoints with multiple access tokens, but with batch querying FQL calls, only the first call returns data, the rest return an empty body.
The only guess I can make is that it is access_token related, but if so I'm sort of at a loss for how to remedy..
Example:
import json
from pyfaceb import *
user1_tk = '...' #valid token (tested)
user1_qry = '...' #valid query (tested unbatched)
user1_rqst = {'method': 'POST', 'relative_url': 'method/fql.query?query=' + user1_qry, 'access_token': user1_tk}
user2_tk = '...' #valid token (tested)
user2_qry = '...' #valid query (tested unbatched)
user2_rqst = {'method': 'POST', 'relative_url': 'method/fql.query?query=' + user2_qry, 'access_token': user2_tk}
batches = [user1_rqst, user2_rqst]
fbg = FBGraph(user1_tk) # use user1_tk as fallback access token (cuz you have to specify one)
data = fbg.get_batch(batches)
print data[0]['body'] #comes back with data, but
print data[1]['body'] #comes back as an empty array.
Both data[0]['code'] and data[1]['code'] are HTTP 200 responses.
If I change the fallback access token to user2_tk, then data[0]['body'] comes back as an empty array (i.e. vice versa). Even though I'm specifying access_tokens for each request (per: https://developers.facebook.com/docs/reference/api/batch/#differentaccesstokens)
Figured it out. The acccess_token needs to be in the request body, as it is a POST:
...
user1_rqst = {
'method': 'POST',
'relative_url': 'method/fql.query?query=' + user1_qry,
'body': 'access_token=' + user1_tk
}
...
user2_rqst = {
'method': 'POST',
'relative_url': 'method/fql.query?query=' + user2_qry,
'body': 'access_token=' + user2_tk
}
When trying to pull data from the youtube gdata api using urllib2.urlopen, I receive a HTTP 403 error. I've turned off the CSRF middleware for debugging purposes, and the view I'm using looks like this:
def videos (request):
params = {}
youtube_search_url = 'http://gdata.youtube.com/feeds/api/videos'
params['order_by'] = 'relevance'
params['max_results'] = 10
params['safeSearch'] = 'strict'
params['v'] = 2
params['key'] = '<developer key>'
f = urllib2.urlopen(youtube_search_url, encoded_params)
...
Any ideas?
When you make an API request, use the X-GData-Key request header to specify your developer key as shown in the following example:
X-GData-Key: key=<developer_key>
Include the key query parameter in the request URL.
http://gdata.youtube.com/feeds/api/videos?q=SEARCH_TERM&key=DEVELOPER_KEY
^^ Straight from the horse's mouth. You are missing the X-GData-Key request header.
The key seems to be required in both url and the header, so given your previous code try this:
req = urllib2.Request(youtube_search_url, encoded_params, { "X-GData-Key": '<developer key>' })
f = urllib2.urlopen(req)