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

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)

Related

How to resolve Falcon CORS preflight request error

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.

Python flask API Return the cookies but set in browser

I have an application in which the python flask API and angular frontend is used I'm able to set cookies and receive in frontend header but unable to fetch the value as shown in below images
the code for python flash is as follows
response.set_cookie('token', secret_token, max_age=900, samesite='Lax')
response.set_cookie('region', user.MMUCode)
response.headers.add('Access-Control-Allow-Headers',
"Origin, X-Requested-With, Content-Type, Accept, x-auth")
return response
Here in angular the code is as follows
return this.httpClient.post<any>(apiUrl + APIRoutes.GenerateOTP, data,
{ observe: 'response' }).pipe(map(response => {
console.log(response.headers.keys()); // all header names
return response.body;
}))
But the response header is having the cookies as shown in below images but not getting set as cookies in browser
Please help me with this. Thanks in advance.
Add a sentence before you add it to the response: cookie.setpath("/");

Streamlabs API 405 response code

I'm trying to use Streamlabs API. Streamlabs API uses Oauth2 for creating apps. So first I send whoever's using my app to an authorization link containing my app's client id and the scopes I want to use.
(Something like this: streamlabs.com/api/v1.0/authorize?client_id=CLIENT-ID-HERE&redirect_uri=REDIRECT-URI&response_type=code&scope=SOME+SCOPES+HERE)
Once I've done that I receive a code at the redirect uri specified. I then use that code to get the access token for permanent access to the connected user's account. I then receive the access token from a POST request that works perfectly... Now I run into the problem. When getting the temporary code before the access token I specified the scopes: "donations.read +donations.create+alerts.write+alerts.create".
When authorizing, the app asks for permission to the different scopes. The scope in focus is "alerts.write" so that I can send test alerts using POST requests. But this doesn't work for some reason. To send a test alert I have to send a POST request to this url: "https://streamlabs.com/api/alerts/send_test_alert"
I've tried doing that in two different ways.
1:
import requests
url = "https://streamlabs.com/api/alerts/send_test_alert"
data = {
"access_token":"UserAccessTokenHere",
"type":"donation"
}
response = requests.post(url=url, data=data)
print(response.text)
2:
import requests
url = "https://streamlabs.com/api/alerts/send_test_alert?access_token=UserAccessTokenHere&type=donation"
response = requests.post(url=url)
print(response.text)
If I do print(response) it prints "Response [405]".
But if I do print(response.text) I get a long HTML document for this page: Error response page
Any ideas what's going wrong with my Python requests? send_test_alert documentation here: Link
I've contacted support and looks like you've made the same error as me.
You're not actually sending a request to the right URL.
You are a sending a request to: "https://streamlabs.com/api/alerts/send_test_alert"
You should be using the URL: "https://streamlabs.com/api/v1.0/alerts/send_test_alert"

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.

CORS - Using AJAX to post on a Python (webapp2) web service

This is going to be long:
Ok so I'm developing a google calendar gadget which sends requests to a Python webapp2 REST api hosted on Google App Engine.
The problem comes when I try to POST something it doesn't allows me because of CORS.
In Chromes' DevTools it says:
Method: OPTIONS.
Status: (failed) Request header field Content-Type is not allowed by Access-Control-Allow-Headers.
Origin https://hq34i4geprnp5vci191ljfuhcoerscl4-a-calendar-opensocial.googleusercontent.com is not allowed by Access-Control-Allow-Origin.
I'm aware that this is because of CORS. Here:
Ajax - 'Origin localhost is not allowed by Access-Control-Allow-Origin'
It says that I have to add
Access-Control-Allow-Origin: *
To the headers, but then again I'm new to ajax and I wonder if it's done this way:
$.ajax({
type: "POST",
url: "https://myapp.appspot.com/service",
contentType: "application/json; charset=utf-8",
data: data,
beforeSend: function (request)
{
request.setRequestHeader("Access-Control-Allow-Origin", "*");
}
success: function(data) {
alert("AJAX done");
}
});
Adding this headers the output is different (which makes me wonder if the origin has been allowed, though I don't really know):
Method: OPTIONS.
Status: (failed) Request header field Content-Type is not allowed by Access-Control-Allow-Headers.
XMLHttpRequest cannot load https://myapp.appspot.com/service. Request header field Access-Control-Allow-Origin is not allowed by Access-Control-Allow-Headers.
I've even found this:
http://james.padolsey.com/javascript/cross-domain-requests-with-jquery/
Which lets me do GET requests, but I'd like to learn how to do them without this.
Also on my webserver I have this:
...
class webService(webapp2.RequestHandler):
options(self):
self.response.write('options')
post(self):
self.response.write('post')
application = webapp2.WSGIApplication([
('/', MainPage),
('/service', webService)
], debug=True)
I don't know if I must add something more to the webserver, nor I've found info saying that I have to.
Also I think I'm near to achieve the CORS request but, I can't find THE Example that explains it all.
Please help.
Ok I fixed it.
First of all I realized here that the headers were sent by the server so I was doing wrong when sending those headers in the AJAX request.
Finally, after searching around the worldwide web I found what I was missing. It was something stupid. I found the page that fixed it all:
http://enable-cors.org/server_appengine.html
So finally everything looks like this:
$.ajax({
type: "POST",
url: "https://myapp.appspot.com/service",
contentType: "application/json; charset=utf-8",
data: data,
success: function(data) {
alert("AJAX done");
}
});
And in the webService:
class webService(webapp2.RequestHandler):
def get(self):
self.response.headers.add_header('Access-Control-Allow-Origin', '*')
self.response.headers['Content-Type'] = 'application/json'
# do something
def post(self):
self.response.headers.add_header('Access-Control-Allow-Origin', '*')
self.response.headers['Content-Type'] = 'application/json'
# do something
def options(self):
self.response.headers['Access-Control-Allow-Origin'] = '*'
self.response.headers['Access-Control-Allow-Headers'] = 'Origin, X-Requested-With, Content-Type, Accept'
self.response.headers['Access-Control-Allow-Methods'] = 'POST, GET, PUT, DELETE'
I just want to point out a detail that might help others:
Browsers differ in how they handle the "Access-Control-Allow-Orgin" header. For example, I found that Chrome blocks cross domain posts when the header value is a wildcard (*) as in the solution code above. It considers it too liberal and wants a specific origin. Yet, other browsers such as IE and FireFox did not care.
So if you want to build a cross browser solution it would be best set the value of "Access-Control-Allow-Origin" to the Origin value sent with the request.
If you're using SSL then you'll encounter some other differences that will need to be tested as well.
And if you need a lightweight solution this can all be done with POJS (plain-old-JavaScript) without resorting to jQuery. Just wire up the window.XDomainRequest for IE8+ and the window.XMLHttpRequest for other browsers and you're in business.
Can simpler with dispatch method
class BaseRequestHandler(webapp2.RequestHandler):
def dispatch(self):
self.response.headers.add_header('Access-Control-Allow-Origin', '*')
self.response.headers.add_header('Access-Control-Allow-Headers', 'Content-Type')
webapp2.RequestHandler.dispatch(self)
class LoginHandler(BaseRequestHandler):
def login(self):
#code here

Categories