How to resolve Falcon CORS preflight request error - python

I'm using falcon_cors v1.4.1 and falcon-cors v1.1.7 to manage the access to the backend API which is hosted in our company's domain. The frontend Angular application is hosted in a different domain (in AWS).
I have the following CORS setup in the backend.
import falcon
from falcon_cors import CORS
cors = CORS(allow_all_origins=True,
allow_all_headers=True,
allow_all_methods=True)
API = falcon.API(middleware=[cors.middleware])
API.add_route(CONFIG.ROOT_PATH + '/query/products', QueryProduct())
...
However, when the Frontend tried to query the API https://mycompanydomain.com/query/products, a CORS error was returned:
Access to XMLHttpRequest at 'https://mycompanydomain.com/query/products'
from origin 'https://mycompany.aws.com' has been blocked by CORS policy:
Response to preflight request doesn't pass access control check:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
With allow_all_origins=True, I would assume the preflight request from all the origins would have been allowed. So not sure how to resolve this issue.

I have backend API which was accessible with GET, but couldn't be successful with POST, due to PREFLIGHT issue, which incurred CORS blockage.
Thus, in this site,
https://newbedev.com/http-request-from-angular-sent-as-options-instead-of-post#:~:text=HTTP%20request%20from%20Angular%20sent%20as%20OPTIONS%20instead,is%20allowed%20from%20a%20particular%20domain%20as%20follows%3A
I have found that, you just simply play with OPTIONS method, which your browser calls to backend for before "ACTUAL" call. this is called Preflight request.
It uses OPTIONS method instead of get/post/put. Thus, this could might help.
If you use Node Js Server:
if (req.method == "OPTIONS")
{
res.writeHead(200, {"Content-Type": "application/json"});
res.end();
}
With PHP, I use this code:
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
header("HTTP/1.1 200 ");
exit;
}
These are my headers in PHP:
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
header("Access-Control-Max-Age: 3600");
header("HTTP/1.1 200");
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Methods, Access-Control-Allow-Headers, Authorization, X-Requested-With, Origin");
Note the OPTIONS method in the headers.
That's it.

Related

Auth0 API can't see URI parameter submitted with Python Requests

I'm trying to do an authentication against Auth0 from a Python script using the PKCE authentication flow, and I'm getting an error that Auth0 can't see exactly one of my URI parameters.
<<CAPITAL LETTERS>> represent missing constants related to the authentication exchange being tested.
import requests
import urllib.parse
def process_auth_callback(authorization_code, callback_uri):
payload = {
'grant_type': 'authorization_code',
'client_id': <<AUTH CLIENT ID>>,
'code_verifier': <<CODE VERIFIER>>,
'code': authorization_code,
'redirect_uri': urllib.parse.quote(callback_uri)
}
r = requests.post('https://<<APP ID>>.us.auth0.com/oauth/token', data=payload)
print(r.request.body)
print(r.text)
process_auth_callback(<<AUTHORIZATION CODE>>, 'http://localhost:1234/login')
I get the error back from Auth0's API:
{"error":"unauthorized_client","error_description":"The redirect URI is wrong. You sent null//null, and we expected http://localhost:1234"}
However, the request body prints as the following: grant_type=authorization_code&client_id=<<AUTH CLIENT ID>>&code_verifier=<<CODE VERIFIER>>&code=<<AUTHORIZATION CODE>>&redirect_uri=http%253A%2F%2Flocalhost%253A1234%2Flogin
This appears to include the correct redirect URI, so I'm not sure why the API is reporting null//null. Is this an issue with how I'm using requests? Something else?
Ah, I found my own answer not long after.
The key is the %253A in the URI encoding in the outgoing request body. (See this answer) Python's requests library is already URI-encoding the parameters, so my URI encoded urllib.parse.quote(callback_uri) is then being encoded again during the data preprocessing prior to send. Auth0's API is unable to parse this and processes it as null//null.

Why does my Flask API endpoint get a CORS error, but other similarly programmed endpoints do not?

Problem
I have a Flask API with two different kinds of routes. I am making requests to my API endpoints from a JavaScript/D3.js application. I need help troubleshooting a CORS error.
Endpoint format
One kind of endpoint follows the format http://127.0.0.1:5000/api/v0.1.0/infrastructure/primary_type/secondary_type
And the other kind follows the format http://127.0.0.1:5000/api/v0.1.0/infrastructure/primary_type/
I am getting a CORS error for the one following the format http://127.0.0.1:5000/api/v0.1.0/infrastructure/primary_type/
CORS Error
Access to fetch at 'http://127.0.0.1:5000/api/v0.1.0/infrastructure/primary_type' from origin 'http://127.0.0.1:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
Endpoint Code
Working Endpoint
#bp.route("<primary_type>/<secondary_type>")
def get_infrastructure(primary_type, secondary_type):
infrastructure = ''
if primary_type == 'null':
infrastructure = shotgun_api.db.infrastructure.find({'properties.type.secondary': secondary_type}, projection = {'_id': False})
else:
infrastructure = shotgun_api.db.infrastructure.find({"$and": [{'properties.type.primary': primary_type},{'properties.type.secondary': secondary_type}]}, projection = {"_id": False})
response = jsonify([resource for resource in infrastructure])
response.headers.add("Access-Control-Allow-Origin", "*")
return response
Endpoint triggering errors
#bp.route('<primary_type>/')
def get_by_primary_type(primary_type):
infrastructure = shotgun_api.db.infrastructure.find({'properties.type.primary': primary_type}, projection = {'_id': False})
response = jsonify([resource for resource in infrastructure])
response.headers.add("Access-Control-Allow-Origin", "*")
return response
Expected behavior
I would expect that using the same response.headers.add... code would provide me with a 200 OK status but it only works for the more complex endpoint for some reason.
Client Side JavaScript/D3.js
for (let i = 0, num_draw_props = lyr.draw_props.length; i < num_draw_props; ++i) {
start_loading_layer();
Promise.all(lyr.draw_props[i].src.map(x => lyr.draw_props[i].d3_fetch(x)))
.then(function(files) {
lyr.context.restore();
lyr.context.save();
return files;
}).then(files => {
transform_layer(lyr.context, transform);
return files
}).then(files => {
console.time('draw_layer')
lyr.draw_props[i].draw_layer(lyr.context, files);
console.timeEnd('draw_layer')
});
}
Where d3_fetch is equal to d3.json(). When src is 'http://127.0.0.1:5000/api/v0.1.0/infrastructure/mines/coal' everything works fine, but when src is http://127.0.0.1:5000/api/v0.1.0/infrastructure/railroads I get the previously mentioned CORS error.
What I've tried
I have tried using Flask-CORS but was unable to get it accessible to my application despite installing it with pip. I would prefer to solve this without using Flask-CORS. I am otherwise at a loss for what to do here and any advice is appreciated.

How to bypass preflight check while setting Access-Control-Allow-Origin header?

I have a flask app running on 127.0.0.1:5000 and another website running on 127.0.0.1:8000. The website has js function making a post request to the flask app, trying to post some dictionary data to the flask app. In the js function i'm using ajax:
$.ajax({
url: "http://127.0.0.1:5000/",
method: "POST",
headers: {
'Access-Control-Allow-Origin':'*',},
data: dict,
});
In the flask app:
#app.route('/',methods=['POST'])
def hello_world():
ok = request.get_json()
print(ok['id'])
return '', 200
Initially in the ajax call, i didn't put any headers. But it prompted me "Cross-Origin Request Blocked". Then I add the header and the request apparently turns into an OPTIONS request, which after googling, suggests pre-flight check. How can I avoid the check? Or why does this check returns a 200 code and the actual post request does not get through? Please give me some help! I am stuck on this for hours. Thanks!
(p.s. i have tried installing flask_cors library and applied it in the flask app but it also does not work)
The Access-Control-Allow-Origin header is a response header - you don't pass it in your request (from the website JS) - you pass it in the response from your Flask app.
If you pass it in the request, it does nothing, EXCEPT make the browser send a preflight OPTIONS request, since it's not a basic request header.
So.
Remove the Access-Control-Allow-Origin request header from your JS
Add the Access-Control-Allow-Options: * response header to your Flask app (I'm not sure how you add response headers in Flask)

Invalid response (404) with Twitter API in Python (and in general)

tl;dr:
I am trying to set headers in a Python HTTP request for the first time and am getting a 404. I would appreciate any help (see bottom).
I have been experimenting with the Twitter API and have not been having much luck. Eventually I am trying to get all of the media (photos) a user has posted (20 or 50 or whatever per fetch)
In my experience with other APIs, this process would go as follows: Get The userID, Make a get request to some endpoint using that userId, get a JSON feed response.
It seems to be much more complicated in Twitter.
For instance, I do not see any URLs where I can attach an access token or client ID. Instead, in their documentation they show a place where I can retrieve my
Comsumer Key, Consumer Secret, Access Token, and, Access Token Secret
If I enter my request URI and "query", it generates an oAuth Signature, which in this case consists of a
Signature base string, Authorization header and cURL command
This is where things get confusing. It says
Important: This will only be valid for a few minutes. Also remember the cURL command will actually execute the request.
So:
Question 1: right away I am wondering how I can use these credentials to retrieve media over an entire day or a weekend if they become invalid only a few minutes later?
Question 2: Using their "exploring API" console, I can test this query (where I am trying to get the user ID for the Ford" twitter account I use GET https://api.twitter.com/1.1/users/lookup.json?screen_name=hyundai
Typing that into the browser alone returns a 404
{"errors": [{"message": "Bad Authentication data","code": 215}]}
But using their little console APP I can pick "O Auth 1 authentication" (using a twitter app I made) and I get the JSON response I want. Examining the request object in the console shows:
GET /1.1/users/lookup.json?screen_name=hyundai HTTP/1.1
Authorization:
OAuth oauth_consumer_key="555SECRET555",oauth_signature_method="HMAC-SHA1",oauth_timestamp="1421370510",oauth_nonce="1869828628",oauth_version="1.0",oauth_token="333DONTHACKMEPLEASE333",oauth_signature="444SECRET444"
Host:
api.twitter.com
X-Target-URI:
https://api.twitter.com
Connection:
Keep-Alive
tl;dr Version:
So, I thought this was the headers object I would need to send from Python (3) to make the identical request. So here is that code:
import urllib.request
header = {
"Authorization" : "OAuth",
"oauth_consumer_key" :"555SECRET555",
"oauth_signature_method": "HMAC-SHA1",
"oauth_timestamp" : "1421362844",
"oauth_nonce":"1201915763",
"oauth_version": "1.0",
"oauth_token":"333CHANGINGTHIS33333",
"oauth_signature":"222CHANGEDTHIS222",
"Host": "api.twitter.com",
"X-Target-URI": "https://api.twitter.com",
"Connection": "Keep-Alive"
}
endpoint = 'https://api.twitter.com/1.1/users/lookup.json?screen_name=hyundai'
q = urllib.request.Request(endpoint, headers=header)
a = urllib.request.urlopen(q)
print(a.read().decode('utf-8'))
But I get a bad, 404 response.
Have I formatted my headers wrong here or is there another way to do this?
If you capture the network traffic from your request (use http not https), you will see that the headers you send are not the same as the header that are expected. This is why you are getting a 404 response.
What you want is something like
header = {
"Authorization": 'OAuth oauth_consumer_key="555SECRET555",oauth_signature_method="HMAC-SHA1",oauth_timestamp="1421362844",oauth_nonce="1201915763",oauth_version="1.0",oauth_token="333CHANGINGTHIS33333",oauth_signature="222CHANGEDTHIS222"',
"Host": "api.twitter.com",
"X-Target-URI": "https://api.twitter.com",
"Connection": "Keep-Alive"
}
Of course, you could always use an OAuth library, such as RAuth or similar, see
Python: OAuth Library for a discussion

google app engine python as backend and angular js as frontend for mobile web

I m trying to implement end to end data sharing between GAE via python and angularJS mobile app using JSON as request body from mobile with contentType as application/json.
I can see in my log that GAE is receiving data and sending a response i.e. {'status': true}.
My Firebug console shows red font(error) for POST request to my GAE server but response status is 200 (ok). Mobile app is getting a 200 status of response but does not get the data.
In my mobile app I'm using $http.post(url, data); to make an http request to GAE and I get this in my Firebug console:
POST http://<code>serverAddress_is_localhost_for_testing</code>:8080/serviceProvider
200 OK
23ms
In the GAE log I can see that the data is processed correctly. This is response code for Python:
self.response.headers['Content-Type'] = 'application/json'
self.response.out.write(response)
Try adding
self.response.headers.add_header("Access-Control-Allow-Origin", "*")
before
self.response.out.write(response)
If that works, replace "*" with your angular/mobile app's domain.
Read more on Cross-origin resource sharing here.

Categories