Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Header Access-Control-Allow-Methods not set #310

Open
alfechner opened this issue Mar 31, 2022 · 8 comments
Open

Header Access-Control-Allow-Methods not set #310

alfechner opened this issue Mar 31, 2022 · 8 comments

Comments

@alfechner
Copy link

alfechner commented Mar 31, 2022

I used the simple usage example from the docs:

from flask import Flask
from flask_cors import CORS

app = Flask(__name__)
CORS(app)

@app.route("/")
def helloWorld():
  return "Hello, cross-origin-world!"

app.run()

I used curl -X "OPTIONS" -I http://127.0.0.1:5000/ to check the headers and received the following output:

HTTP/1.1 200 OK
Server: Werkzeug/2.1.0 Python/3.9.2
Date: Thu, 31 Mar 2022 10:32:07 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 26
Access-Control-Allow-Origin: *

For my understanding the Access-Control-Allow-Methods header is missing.

I changed CORS(app) to CORS(app, methods=["GET"]). Still the same result.

My requirements.txt looks like this:

Flask==2.1.1
flask-cors==3.0.10

This causes the OPTIONS preflight check in our apps to fail. Are we doing something wrong or is this an issue?

@fatzh
Copy link

fatzh commented Apr 18, 2022

We're facing the same issue, the Access-Control-Allow-Methods is only returned in the following cases:

  • if the header Access-Control-Request-Method AND Origin is set in the request
  • if the header Access-Control-Request-Method AND CORS_SEND_WILDCARD is set to True

Something changed (I guess?) but not really sure is it's something that needs fixing here on in the front app...

@fatzh
Copy link

fatzh commented Apr 20, 2022

the preflight queries are automatically handled, and looking at the developer tools in chrome it looks like the response is not always the same. Our scenario is fairly standard:

  • user makes a request to the /api/me/ endpoint, preflight is sent:
OPTIONS /api/me/ HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate
Accept-Language: en-GB,en;q=0.9,fr-FR;q=0.8,fr;q=0.7,de-DE;q=0.6,de;q=0.5,en-US;q=0.4
Access-Control-Request-Headers: authorization
Access-Control-Request-Method: GET
Cache-Control: no-cache
Connection: keep-alive
Host: mingus:5000
Origin: http://mingus:1234
Pragma: no-cache
Referer: http://mingus:1234/
Sec-Fetch-Mode: cors
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36

preflight response looks good:

HTTP/1.1 200 OK
Server: Werkzeug/2.1.1 Python/3.8.7
Date: Wed, 20 Apr 2022 07:52:23 GMT
Content-Type: text/html; charset=utf-8
Allow: GET, PATCH, PUT, HEAD, DELETE, OPTIONS, POST
Access-Control-Allow-Origin: http://mingus:1234
Access-Control-Allow-Headers: authorization
Access-Control-Allow-Methods: DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT
Vary: Origin
Content-Length: 0
  • token (JWT) has expired (401 with token expired message), browser makes a refresh request, preflight is sent, response has all the headers, good
  • and retries the first request with the fresh token, a new preflight is sent, same as the first:
OPTIONS /api/me/ HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate
Accept-Language: en-GB,en;q=0.9,fr-FR;q=0.8,fr;q=0.7,de-DE;q=0.6,de;q=0.5,en-US;q=0.4
Access-Control-Request-Headers: authorization
Access-Control-Request-Method: GET
Cache-Control: no-cache
Connection: keep-alive
Host: mingus:5000
Origin: http://mingus:1234
Pragma: no-cache
Referer: http://mingus:1234/
Sec-Fetch-Mode: cors
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36

But this time the response looks like this:

HTTP/1.1 405 METHOD NOT ALLOWED
Server: Werkzeug/2.1.1 Python/3.8.7
Date: Wed, 20 Apr 2022 07:52:24 GMT
Content-Type: text/html; charset=utf-8
Allow: GET, PATCH, PUT, HEAD, DELETE, OPTIONS, POST
Content-Length: 178
Access-Control-Allow-Origin: http://mingus:1234
Vary: Origin

i.e. the Access-Control-Allow-Methods header is missing.

All this happens very quickly, could it be a cache problem ? I'm trying to setup add more logs to debug this, but this is all happening in a blueprint and somehow the logs gets lost, will report if I manage this.

@fatzh
Copy link

fatzh commented Apr 20, 2022

ok got the debug logs activated, and indeed the headers are not sent back:

[2022-04-20 17:18:34,288] DEBUG in core: CORS request received with 'Origin' http://mingus:1234
[2022-04-20 17:18:34,288] DEBUG in core: The request's Origin header matches. Sending CORS headers.
[2022-04-20 17:18:34,289] DEBUG in core: Settings CORS headers: MultiDict([('Access-Control-Allow-Origin', 'http://mingus:1234'), ('Access-Control-Allow-Headers', 'authorization'), ('Access-Control-Allow-Methods', 'DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT'), ('Vary', 'Origin')])
192.168.1.52 - - [20/Apr/2022 17:18:34] "OPTIONS /api/me/ HTTP/1.1" 200 -
[2022-04-20 17:18:34,319] DEBUG in core: CORS request received with 'Origin' http://mingus:1234
[2022-04-20 17:18:34,319] DEBUG in core: The request's Origin header matches. Sending CORS headers.
[2022-04-20 17:18:34,319] DEBUG in core: Settings CORS headers: MultiDict([('Access-Control-Allow-Origin', 'http://mingus:1234'), ('Vary', 'Origin')])
192.168.1.52 - - [20/Apr/2022 17:18:34] "GET /api/me/ HTTP/1.1" 401 -
[2022-04-20 17:18:34,334] DEBUG in core: CORS request received with 'Origin' http://mingus:1234
[2022-04-20 17:18:34,334] DEBUG in core: The request's Origin header matches. Sending CORS headers.
[2022-04-20 17:18:34,335] DEBUG in core: Settings CORS headers: MultiDict([('Access-Control-Allow-Origin', 'http://mingus:1234'), ('Access-Control-Allow-Headers', 'authorization'), ('Access-Control-Allow-Methods', 'DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT'), ('Vary', 'Origin')])
192.168.1.52 - - [20/Apr/2022 17:18:34] "OPTIONS /api/refresh-token/ HTTP/1.1" 200 -
...
[2022-04-20 17:18:34,350] DEBUG in core: CORS request received with 'Origin' http://mingus:1234
[2022-04-20 17:18:34,350] DEBUG in core: The request's Origin header matches. Sending CORS headers.
[2022-04-20 17:18:34,351] DEBUG in core: Settings CORS headers: MultiDict([('Access-Control-Allow-Origin', 'http://mingus:1234'), ('Vary', 'Origin')])
192.168.1.52 - - [20/Apr/2022 17:18:34] "POST /api/refresh-token/ HTTP/1.1" 200 -
[2022-04-20 17:18:34,378] DEBUG in core: CORS request received with 'Origin' http://mingus:1234
[2022-04-20 17:18:34,378] DEBUG in core: The request's Origin header matches. Sending CORS headers.
[2022-04-20 17:18:34,378] DEBUG in core: Settings CORS headers: MultiDict([('Access-Control-Allow-Origin', 'http://mingus:1234'), ('Vary', 'Origin')])
192.168.1.52 - - [20/Apr/2022 17:18:34] "<hidden post data>GET /api/me/ HTTP/1.1" 405 -

So sometime we only get Settings CORS headers: MultiDict([('Access-Control-Allow-Origin', 'http://mingus:1234'), ('Vary', 'Origin')]) and this result in a 405. All the preflight requests are handled by the browser, but I'm not sure anymore if I can trust the developer tools to show really what's happening I'll try to add more logging in the coming days...

@lewiswilliam
Copy link

-H "Access-Control-Request-Method: get" -H 'Access-Control-Request-Headers: If-Modified-Since,Cache-Control'
pass the above and check if you get the required headers back. I got what i wanted by doing that.

@fatzh
Copy link

fatzh commented Apr 20, 2022

I tried already above, manually it works as soon as I explicitly set Access-Control-Request-Method.

But in real life, I don't really control how the preflight requests are made, that's all browser driven... I get the same problem with firefox by the way.

But now I start to suspect our frontend dev... I need to talk to him and I'll update.

@fatzh
Copy link

fatzh commented Apr 21, 2022

after more investigation and logging, this seems to happen only when flask runs in development mode, where some payload get somehow injected in the request.environ['REQUEST_METHOD'] value, so instead of a simple GET we get something like {"data": "123"}GET.

When running with gunicorn, it works fine. So I'll investigate further if I can setup a simple case where this breaks I'll follow up with flask/werkzeug.

thanks for your help, nothing more from my side.

@EdmundsEcho
Copy link

EdmundsEcho commented Jul 19, 2022

@fatzh Any good news to report :)) ?

Ironically, I don't need CORS in production. It's only in dev/debugging mode that CORS is important to have working. I tried to set the header manually with the origin '*'... nothing seems to get the Response to include the header.

@projects_blueprint.route("/v1/projects/<id>", methods=['GET', 'POST', 'PATCH', 'DELETE'])  # noqa: E501
def projects(id):
    response = postgrest_request("get", "http://restapi:3000/projects")
    return response.text, response.status_code

Note: I have CORS(app) in the root of the app. The manual attempts are not shown - but I could have been doing something wrong.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants