I'm trying to request a route (graphql) that is being handled by a GraphQLApp. It works well when I send requests from postman but it fails when going over preflight checks (requesting from my web browser):
Access to fetch at 'http://192.168.64.2:30540/graphql' from origin 'http://localhost:8080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.
I slightly modified the code from starlette/middleware/cors.py to have a little bit more information on what is happening. The response content generated by preflight_response is Disallowed CORS method (POST), header (access-control-allow-origin), header (authorization), header (content-type).
OPTIONS request details
{
"startedDateTime": "2020-01-14T17:33:42.735Z",
"time": 5.767000009655021,
"request": {
"method": "OPTIONS",
"url": "http://192.168.64.2:30540/graphql",
"httpVersion": "HTTP/1.1",
"headers": [
{
"name": "Host",
"value": "192.168.64.2:30540"
},
{
"name": "Connection",
"value": "keep-alive"
},
{
"name": "Pragma",
"value": "no-cache"
},
{
"name": "Cache-Control",
"value": "no-cache"
},
{
"name": "Access-Control-Request-Method",
"value": "POST"
},
{
"name": "Origin",
"value": "http://foobar:8080"
},
{
"name": "User-Agent",
"value": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36"
},
{
"name": "Access-Control-Request-Headers",
"value": "access-control-allow-origin,authorization,content-type"
},
{
"name": "Accept",
"value": "*/*"
},
{
"name": "Referer",
"value": "http://foobar:8080/public/index.html"
},
{
"name": "Accept-Encoding",
"value": "gzip, deflate"
},
{
"name": "Accept-Language",
"value": "fr,en-US;q=0.9,en;q=0.8"
}
],
"queryString": [],
"cookies": [],
"headersSize": 541,
"bodySize": 0
},
"response": {
"status": 400,
"statusText": "Bad Request",
"httpVersion": "HTTP/1.1",
"headers": [
{
"name": "date",
"value": "Tue, 14 Jan 2020 17:33:41 GMT"
},
{
"name": "server",
"value": "uvicorn"
},
{
"name": "access-control-allow-origin",
"value": "*"
},
{
"name": "access-control-allow-methods",
"value": "GET"
},
{
"name": "access-control-max-age",
"value": "600"
},
{
"name": "content-length",
"value": "49"
},
{
"name": "content-type",
"value": "text/plain; charset=utf-8"
}
],
"cookies": [],
"content": {
"size": 49,
"mimeType": "text/plain",
"compression": 0,
"text": "Disallowed CORS method, headers, headers, headers"
},
"redirectURL": "",
"headersSize": 239,
"bodySize": 49,
"_transferSize": 288
},
"cache": {},
"timings": {
"blocked": 3.1320000051520767,
"dns": -1,
"ssl": -1,
"connect": -1,
"send": 0.07699999999999996,
"wait": 1.541999995244667,
"receive": 1.0160000092582777,
"_blocked_queueing": 2.0570000051520765
}
}
I also have a regular access point (admin) that I can request without any problem on both postman and browser.
My code looks like so:
graphql_app = GraphQLApp(schema=schema, executor_class=AsyncioExecutor)
routes = [
Route('/graphql', graphql_app),
Route('/admin', admin_login_token, methods=["POST"]),
]
middleware = [
Middleware(TrustedHostMiddleware, allowed_hosts=list(settings.WEB.ALLOWED_HOSTS)),
Middleware(CORSMiddleware, allow_origins=['*']),
Middleware(AuthenticationMiddleware, backend=BasicAuthBackend()),
]
app = Starlette(
debug=True,
routes=routes,
middleware=middleware
)
I also can cheat a little by allowing all "problematic" headers/methods to my middleware (but I guess if these headers are not allowed by default that must be for a reason):
Middleware(
CORSMiddleware,
allow_origins=['*'],
+ allow_methods=['POST', 'GET'],
+ allow_headers=['access-control-allow-origin', 'authorization', 'content-type'],
)
That's also strange because CORS middleware never complain about these headers on POST requests, but only on OPTIONS requests.
Did I do something wrong or is there a problem in starlette?
Stumbled upon the same problem, and adding content-type to allow_headers solved it. However, according to the documentation, Content-Type should be a white listed header. My guess is that since the header is sent by the client in lowercase, the white list test fails.
Most helpful comment
Stumbled upon the same problem, and adding
content-typetoallow_headerssolved it. However, according to the documentation,Content-Typeshould be a white listed header. My guess is that since the header is sent by the client in lowercase, the white list test fails.