Search code examples
pythonflaskflask-cors

Not getting Access-Control-Allow-Headers and Access-Control-Max-Age with flask-cors


code is as follows:

from flask import Flask, Response, request
import json
from flask_cors import CORS
from waitress import serve

app = Flask(__name__)
CORS(app, resources={r"/app/*": {"origins": "http://localhost:3000",
                                 "allow_headers": ["Origin", "Authorization", "X-Frame-Options", "X-Requested-With", "DNT", "User-Agent", "If-Modified-Since", "Cache-Control", "Range", "X-Real-IP", "HOST", "X-NginX-Proxy", "Content-Type", "If-Match"],
                                 "expose_headers": ["ETag", "Content-Length", "Content-Range", "Access-Control-Allow-Origin"],
                                 "max_age": "3600"}})


@app.route('/app/compute', methods=['GET', 'POST', 'PUT'])
def compute():
    input = request.json
    responsedict = dict()
    responsedict['customerid'] = 'customer A'
    responsedict['loan_amount'] = 0
    return Response(json.dumps(responsedict), status=200, mimetype="application/json")

serve(app, port=5000, host="0.0.0.0")

requirements.txt is as follows:

Flask==2.0.2
Flask-Cors==3.0.10
waitress==2.1.1

I am not getting following headers in response of Options request: Access-Control-Allow-Headers and Access-Control-Max-Age

postman screenshot showing missing headers

Any guidance will be appreciated.


Solution

  • According to the extension's code:

        # This is a preflight request
        # http://www.w3.org/TR/cors/#resource-preflight-requests
        if request_method == 'OPTIONS':
            acl_request_method = request_headers.get(ACL_REQUEST_METHOD, '').upper()
    
            # If there is no Access-Control-Request-Method header or if parsing
            # failed, do not set any additional headers
            if acl_request_method and acl_request_method in options.get('methods'):
    
                # If method is not a case-sensitive match for any of the values in
                # list of methods do not set any additional headers and terminate
                # this set of steps.
                headers[ACL_ALLOW_HEADERS] = get_allow_headers(options, request_headers.get(ACL_REQUEST_HEADERS))
                headers[ACL_MAX_AGE] = options.get('max_age')
                headers[ACL_METHODS] = options.get('methods')
            else:
                LOG.info("The request's Access-Control-Request-Method header does not match allowed methods. CORS headers will not be applied.")
    

    So you need to send an OPTIONS request, and have the Access-Control-Request-Method header. And for getting the Access-Control-Allow-Headers header in response, you need the Access-Control-Request-Headers in your request.

    This request will work:

    curl -vvv 'http://localhost:8000/app/compute2' -X OPTIONS -H "Access-Control-Request-Method: POST"
    

    sample response:

    [ilias@yellowhat ~] > curl -vvv 'http://localhost:8000/app/compute' -X OPTIONS -H "Access-Control-Request-Method: post"
    *   Trying 127.0.0.1:8000...
    * Connected to localhost (127.0.0.1) port 8000 (#0)
    > OPTIONS /app/compute HTTP/1.1
    > Host: localhost:8000
    > User-Agent: curl/7.79.1
    > Accept: */*
    > Access-Control-Request-Method: post
    > 
    * Mark bundle as not supporting multiuse
    < HTTP/1.1 200 OK
    < Server: Werkzeug/2.1.1 Python/3.10.4
    < Date: Tue, 19 Apr 2022 14:18:33 GMT
    < Content-Type: text/html; charset=utf-8
    < Allow: POST, GET, HEAD, PUT, OPTIONS
    < Access-Control-Allow-Origin: http://localhost:3000
    < Access-Control-Expose-Headers: Access-Control-Allow-Origin, Content-Length, Content-Range, ETag
    < Access-Control-Max-Age: 4444
    < Access-Control-Allow-Methods: DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT
    < Content-Length: 0
    < 
    * Connection #0 to host localhost left intact
    [ilias@yellowhat ~] > 
    

    for 2nd header as well:

    curl -vvv 'http://localhost:8000/app/compute' -X OPTIONS -H "Access-Control-Request-Method: get" -H 'Access-Control-Request-Headers: If-Modified-Since,Cache-Control'
    

    response:

    [ilias@yellowhat flask_cors] > curl -vvv 'http://localhost:8000/app/compute' -X OPTIONS -H "Access-Control-Request-Method: get" -H 'Access-Control-Request-Headers: If-Modified-Since,Cache-Control'
    *   Trying 127.0.0.1:8000...
    * Connected to localhost (127.0.0.1) port 8000 (#0)
    > OPTIONS /app/compute HTTP/1.1
    > Host: localhost:8000
    > User-Agent: curl/7.79.1
    > Accept: */*
    > Access-Control-Request-Method: get
    > Access-Control-Request-Headers: If-Modified-Since,Cache-Control
    > 
    * Mark bundle as not supporting multiuse
    < HTTP/1.1 200 OK
    < Server: Werkzeug/2.1.1 Python/3.10.4
    < Date: Tue, 19 Apr 2022 14:35:26 GMT
    < Content-Type: text/html; charset=utf-8
    < Allow: GET, POST, PUT, HEAD, OPTIONS
    < Access-Control-Allow-Origin: http://localhost:3000
    < Access-Control-Expose-Headers: Access-Control-Allow-Origin, Content-Length, Content-Range, ETag
    < Access-Control-Allow-Headers: Cache-Control, If-Modified-Since
    < Access-Control-Max-Age: 4444
    < Access-Control-Allow-Methods: DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT
    < Content-Length: 0
    < 
    * Connection #0 to host localhost left intact
    [ilias@yellowhat flask_cors] > 
    

    these requests will not work:

    curl -vvv 'http://localhost:8000/app/compute' -X OPTIONS -H "Access-Control-Request-Method: somethinghere"
    curl -vvv 'http://localhost:8000/app/compute' -X OPTIONS
    curl -vvv 'http://localhost:8000/app/compute' -H "Access-Control-Request-Method: POST"