Permitting CORS in Flask - python

I've a flask endpoint where I've permitted CORS in the following manner.
app = Flask(__name__)
CORS(app, resources={r"/api/*": {"origins": "*"}})
app.register_blueprint(store, url_prefix='/api/')
I still run into the following issue.
Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true' when the request's credentials mode is 'include'. Origin 'http://something.com:8888' is therefore not allowed access.
Any suggestions as to how I can fix this.

try this:
#Add these imports
from flask import jsonify
from flask_cors import CORS
#Add an app level config in this format
app = Flask(__name__)
CORS(autoINFER_app, resources={r"/*": {"origins": "*"}}, send_wildcard=True)
#While returning the GETs add this line
response = jsonify(all_dict)
response.headers.add('Access-Control-Allow-Origin', '*')
return response
This should take care of all permutations which might cause this.

Related

How to configure basepath in flask restful api application?

I want to set a basepath for my flask application. I have mentioned one example below.
basepath = 'http://localhost:3000/api'
i have two api call one is GET and other one is POST .
from flask import Flask
from flask_restful import Api
app = Flask(__name__)
api = Api(app)
api.add_resource(CreateUser, "/v1/user/create/")
api.add_resource(CreateUser, "/v1/user/details")
class CreateUser(Resource):
def post(self):
# Code for creating a user
def get(self):
# Code for get the details of user.
So here, if i want to create the user then my url will be http://localhost:3000/api/v1/user/create/
so same for GET also . So how do i achieve this ?
Initialize your Api with the path prefix:
from flask import Flask
from flask_restful import Api
app = Flask(__name__)
api = Api(app, "/api")
...
You can't change the host and port this way, you'll have to run flask with parameters:
flask run --host=127.0.0.1 --port=3000
Or you could do
from flask import Flask
from flask_restful import Resource, Api
app = Flask(__name__)
api = Api(app, "/api")
...
if __name__ == "__main__":
app.run(host="127.0.0.1", port="3000")
Please keep in mind this is not intended for production environments, only for local testing. Please see https://flask.palletsprojects.com/en/1.1.x/tutorial/deploy/ for using in a production environment.
If you want to get those values from basepath, one option would be purl:
url = purl.URL('http://localhost:3000/api')
url.host() # --> "localhost"
url.port() # --> 3000
url.path() # --> "/api"

CORS request did not succeed in python flask-socketio

I need help in debugging -the Same Origin Policy disallows reading the remote resource at https://some-domain.com. (Reason: CORS request did not succeed) in python flask-socketio error.
I am working on a chat application using python flask-socketio. In previously I have created that application in local and it works fine as expected, while I move the below code to the server it shows the above error. The client code runs in the https servers and server code also runs on the https server I don't know why that error shows.
I have attached my code below and please give a better solution to me.
server.py
import json
import os
from flask import Flask, render_template, request,session
from flask_socketio import SocketIO, send, emit
from datetime import timedelta,datetime
from flask_cors import CORS
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secretkey'
app.config['DEBUG'] = True
app.config['CORS_HEADERS'] = 'Content-Type'
cors = CORS(app, resources={r"/*": {"origins": "*"}})
socketio = SocketIO(app)
users = {}
#app.before_request
def make_session_permanent():
session.permanent = True
app.permanent_session_lifetime = timedelta(minutes=1)
#app.route('/')
##cross_origin(origin='*',headers=['Content- Type','Authorization'])
def index():
return render_template('index.html')
#socketio.on('connect')
def connect():
print("connected");
#app.route('/orginate')
def orginate():
socketio.emit('server orginated', 'Something happened on the server!')
return '<h1>Sent!</h1>'
#socketio.on('username')
def receive_username(username):
users[username] = request.sid
#users.append({username : request.sid})
#print(users)
emit('userList', users, broadcast=True)
print('Username added!')
print(users)
if _name_ == '__main__':
socketio.run(app,host='xxx.xxx.xx.x',port=5001)
client.js
var socket = io.connect("https://xxx.xxx.xx.x:5001/",{secure:false});
Screenshot 1:
This screenshot explains the access-control-allow-orgin works fine for images under static folder in flask framework
Screenshot 2:
This screenshot explains there is no access-control-orgin for socket call
You are using Flask-CORS to set up CORS on your Flask routes. You are missing a similar set up for Flask-SocketIO:
socketio = SocketIO(app, cors_allowed_origins=your_origins_here)
You can use '*' as the value to allow all origins (which I do not recommend), or set a single origin as a string, or a list of origins as a list of strings.

Flask_dance with Google API; Missing required parameter: refresh_token

I trid to make authorization system with flask_dance and Google.
I was successful in authorize first but after a while, the program caused this error even though I didn't change it at all.
My whole code is here (It's almost the same as the tutorial one though
from flask import Flask, redirect, url_for
from flask_dance.contrib.google import make_google_blueprint, google
app = Flask(__name__)
app.secret_key = "supersekrit"
blueprint = make_google_blueprint(
client_id="",
client_secret="",
scope=["profile", "email"]
)
app.register_blueprint(blueprint, url_prefix="/login")
#app.route("/")
def index():
if not google.authorized:
return redirect(url_for("google.login"))
resp = google.get("/oauth2/v2/userinfo")
assert resp.ok, resp.text
return "You are {email} on Google".format(email=resp.json()["email"])
if __name__ == "__main__":
app.run()
How can I fix this error?
This problem seems to be the one referenced in this Github issue. The suggested solution is to request offline access:
google_blueprint = make_google_blueprint(
client_id='',
client_secret='',
scope=['profile', 'email'],
offline=True
)

Flask access request data when uploading file with angular

I'm uploading a file using angular and try to access the uploaded file in flask.
This is no problem and works fine. However, when I add more request parameters I cannot seem to find them in the flask request object.
For example, uploading a file using ngFileUpload (https://github.com/danialfarid/ng-file-upload) I can specify more meta-information like this:
$scope.upload = function (file) {
Upload.upload({
url: '/api/upload',
data: {file: file, 'username': $scope.username}
})
};
where username is extra meta-information.
Here's the flask code (using Flask-Restful):
from flask import Flask, request, Response
from flask.ext.restful import Api, Resource
ALLOWED_EXTENSIONS = {'csv'}
def allowed_file(fn):
return '.' in fn and fn.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS
app = Flask(__name__)
api = Api(app)
class Upload(Resource):
def post():
file = request.files['file']
fn = file.filename
if file and allowed_file(fn):
try:
# code for saving file
return Response(status=200)
except:
return Response(status=500)
return Response(status=500)
api.add_resource(Upload, '/api/upload')
In flask I can access the file through request.files['file'], but the username information/variable is nowhere to be found.
Is this not possible in flask, am I missing something, or what's going on here?
I actually think #ciacicode was right to ask you about your python code.
You are probably running into a CORS violation with Angular calling Python.
Add an import
See Flask-CORS: http://flask-cors.corydolphin.com/en/latest/index.html
from flask.ext.cors import CORS
Add CORS to your app
Simple addition to your code:
app = Flask(__name__)
cors = CORS(app)
api = Api(app)
Adding CORS made your code sample run for me.
If the CORS is not doing anything for you, then use request.values['username']

Flask RESTful cross-domain issue with Angular: PUT, OPTIONS methods

I've developed a small write-only REST api with Flask Restful that accepts PUT request from a handful of clients that can potentially have changing IP addresses. My clients are embedded Chromium clients running an AngularJS front-end; they authenticate with my API with a simple magic key -- it's sufficient for my very limited scale.
I'm testing deploying my API now and I notice that the Angular clients are attempting to send an OPTIONS http methods to my Flask service. My API meanwhile is replying with a 404 (since I didn't write an OPTIONS handler yet, only a PUT handler). It seems that when sending cross-domain requests that are not POST or GET, Angular will send a pre-flight OPTIONS method at the server to make sure the cross-domain request is accepted before it sends the actual request. Is that right?
Anyway, how do I allow all cross-domain PUT requests to Flask Restful API? I've used cross-domaion decorators with a (non-restful) Flask instance before, but do I need to write an OPTIONS handler as well into my API?
With the Flask-CORS module, you can do cross-domain requests without changing your code.
from flask.ext.cors import CORS
app = Flask(__name__)
cors = CORS(app, resources={r"/api/*": {"origins": "*"}})
https://pypi.python.org/pypi/Flask-Cors
https://github.com/corydolphin/flask-cors
Update
As Eric suggested, the flask.ext.cors module is now deprecated, you should rather use the following code:
from flask_cors import CORS
app = Flask(__name__)
cors = CORS(app, resources={r"/api/*": {"origins": "*"}})
You can use the after_request hook:
#app.after_request
def after_request(response):
response.headers.add('Access-Control-Allow-Origin', '*')
response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization')
response.headers.add('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE')
return response
I resolved the issue by rewriting my Flask backend to answer with an Access-Control-Allow-Origin header in my PUT response. Furthermore, I created an OPTIONS handler in my Flask app to answer the options method by following what I read in the http RFC.
The return on the PUT method looks like this:
return restful.request.form, 201, {'Access-Control-Allow-Origin': '*'}
My OPTIONS method handler looks like this:
def options (self):
return {'Allow' : 'PUT' }, 200, \
{ 'Access-Control-Allow-Origin': '*', \
'Access-Control-Allow-Methods' : 'PUT,GET' }
#tbicr is right: Flask DOES answer the OPTIONS method automatically for you. However, in my case it wasn't transmitting the Access-Control-Allow-Origin header with that answer, so my browser was getting a reply from the api that seemed to imply that cross-domain requests were not permitted. I overloaded the options request in my case and added the ACAO header, and the browser seemed to be satisfied with that, and followed up OPTIONS with a PUT that also worked.
How about this workaround:
from flask import Flask
from flask.ext import restful
from flask.ext.restful import Api
from flask.ext.sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config.from_object('config')
#flask-sqlalchemy
db = SQLAlchemy(app)
#flask-restful
api = restful.Api(app)
#app.after_request
def after_request(response):
response.headers.add('Access-Control-Allow-Origin', '*')
response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization')
response.headers.add('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE')
return response
import views
I took this from this tutorial. Works very good. actually, i think this is the best approach I've seen so far.
Returning {'Access-Control-Allow-Origin': '*'} on each endpoint, doesn't seems to be efficient since you have to add it on every endpoint. a bit anoying..., at least for me.
I tried #cors.crossdomain(origin='*') but, looks like it only works with GET request.
You're right, OPTIONS method called every time before real request in browser. OPTIONS response have allowed methods and headers. Flask automatically process OPTIONS requests.
To get access for cross domain request you API must have Access-Control-Allow-Origin header. It can contain specific domains, but if you want allow requests from any domains you can set it to Access-Control-Allow-Origin: *.
To set up CORS for flask you can look at one extension code or try use this extension: https://github.com/wcdolphin/flask-cors/blob/master/flask_cors.py.
To set up CORS for flask-restful look this pull requests: https://github.com/twilio/flask-restful/pull/122 and https://github.com/twilio/flask-restful/pull/131. But looks like flask-restful does not support it by default yet.
Just an update to this comment. Flask CORS is the way to go, but the flask.ext.cors is deprecated.
use:
from flask_cors import CORS
To allow remote CORS requests on your web service api, you can simply initialize your flask restful API like this:
from flask import Flask
from flask_restful import reqparse, abort, Api, Resource
from flask_cors import CORS
app = Flask(__name__)
cors = CORS(app, resources={r"*": {"origins": "*"}})
api = Api(app)
This adds the CORS header to your api instance and allows a CORS request on every path from every origin.
I like to use a decoration to solve.
def cross_origin(origin="*"):
def cross_origin(func):
#functools.wraps(func)
def _decoration(*args, **kwargs):
ret = func(*args, **kwargs)
_cross_origin_header = {"Access-Control-Allow-Origin": origin,
"Access-Control-Allow-Headers":
"Origin, X-Requested-With, Content-Type, Accept"}
if isinstance(ret, tuple):
if len(ret) == 2 and isinstance(ret[0], dict) and isinstance(ret[1], int):
# this is for handle response like: ```{'status': 1, "data":"ok"}, 200```
return ret[0], ret[1], _cross_origin_header
elif isinstance(ret, basestring):
response = make_response(ret)
response.headers["Access-Control-Allow-Origin"] = origin
response.headers["Access-Control-Allow-Headers"] = "Origin, X-Requested-With, Content-Type, Accept"
return response
elif isinstance(ret, Response):
ret.headers["Access-Control-Allow-Origin"] = origin
ret.headers["Access-Control-Allow-Headers"] = "Origin, X-Requested-With, Content-Type, Accept"
return ret
else:
raise ValueError("Cannot handle cross origin, because the return value is not matched!")
return ret
return _decoration
return cross_origin
And then, Use decoration in your restful api.
class ExampleRestfulApi(Resource)
#cross_origin()
def get(self):
# allow all cross domain access
pass
#cross_origin(origin="192.168.1.100")
def post(self):
# allow 192.168.1.100 access
pass
I was facing the multiple types of CORS issue while connecting to my flask rest api from angular and tried almost all the approaches.
If you want to give access to all the websites without any restriction you can add below code in you app.py script :
from flask_cors import CORS , cross_origin
cors = CORS(app, resources={r"/*": {"origins": "*"}})
this will work, but its recommended to have some security which you can always edit in origin

Categories