I am trying to enable CORS in FastAPI on my localhost with credentials enabled. According to the docs we must explicitly set allow_origins in this case:
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware, Response
app = FastAPI()
app.add_middleware(
CORSMiddleware, allow_origins=['http://localhost:8000'],
allow_credentials=True, allow_methods=['*'], allow_headers=['*'])
@app.get('/')
def main():
return Response('OK', status_code=200)
However, when making a request it does fail with
CORS Missing Allow Origin [Cross-source (cross-origin) request blocked: The same origin policy disallows reading the remote resource at
http://[::1]:8000/create_session/none
. (Reason: CORS header'Access-Control-Allow-Origin'
is missing). Status code: 200.]
const response = await fetch('http://localhost:8000/', {credentials: "include"});
The client is Firefox with a local file (file://.../main.html) opened.
I already tried all solutions from How can I enable CORS in FastAPI?. What's wrong?
Edit: My question is not a duplicate of How to access FastAPI backend from a different machine/IP on the same local network?, because the server and the client are on the same (local)host. Nevertheless I tried setting the suggested --host 0.0.0.0 and the error remains the same.
Also it's not a duplicate of FastAPI is not returning cookies to React frontend, because it suggests setting the CORS origin in the same way as the official docs, which does not work as I described above.
Since you haven't provided the actual CORS error in your question, it should be specified here for future readers visiting this post. When sending a JavaScript HTTP request to a server, in this case a FastAPI backend, through a local HTML file that has been loaded into the browser via a file:///
URL—e.g., by dragging-dropping the file into the browser or just double-clicking the file—with the URL in the browser's address bar looking like this:
file:///C:/...index.html
browsers that apply CORS would output the following errors. If you are using Chrome (or a chromium-based) browser, you would see a CORS error
(Cross-Origin Resource Sharing error: MissingAllowOriginHeader
) under the Status
column in the Network
tab/section, indicating that the response to the CORS request is missing the required Access-Control-Allow-Origin
header, in order to determine whether or not the resource can be accessed. The error is made more clear by looking at the console, after submitting the request:
Access to fetch at
'http://localhost:8000/'
from origin'null'
has been blocked by CORS policy: No'Access-Control-Allow-Origin'
header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.GET
http://localhost:8000/
net::ERR_FAILED 200 (OK)
If you are using FireFox instead, you would see a similar error in the console:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at
http://localhost:8000/
. (Reason: CORS header'Access-Control-Allow-Origin'
missing).Status code: 200
The reason for the error(s) raised above is that you are trying to perform a cross-origin request through a script that is running via a file:///
URL. In that case, the client's origin is null
, but you only added http://localhost:8000
to the allowed origins. Thus, a quick fix would be to add null
to the origins
list, e.g., Access-Control-Allow-Origin: null
. In FastAPI, you could do that as shown in the example below (however, it is not recommended to do so—see more details below the example).
app.py
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
origins = ['null'] # NOT recommended - see details below
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.get('/')
def main():
return 'ok'
index.html
<!DOCTYPE html>
<html>
<body>
<h1>Send JS request</h1>
<button onclick="getData()">Click me</button>
<script>
function getData() {
fetch('http://localhost:8000/')
.then(resp => resp.json()) // or resp.text(), etc.
.then(data => {
console.log(data);
})
.catch(error => {
console.error(error);
});
}
</script>
</body>
</html>
However, it is not recommended doing that, as it is insecure. As described in MDN's documentation:
Note:
null
should not be used: "It may seem safe to returnAccess-Control-Allow-Origin: "null"
, but the serialization of the Origin of any resource that uses a non-hierarchical scheme (such asdata:
orfile:
) and sandboxed documents is defined to be"null"
. Many User Agents will grant such documents access to a response with anAccess-Control-Allow-Origin: "null"
header, and any origin can create a hostile document with a"null"
Origin. The"null"
value for the ACAO header should therefore be avoided."
Another great article on the risks of using the null
origin, as well as misconfiguring CORS in general, can be found here.
As explained in several related questions, as shown here and here, one should rather serve the HTML file(s), e.g., index.html
above, using a local web server. FastAPI can do that for you as well, using the HTMLResponse
or even Jinja2Templates
, as demonstrated in this answer, this answer, as well as this, this and this. Thus, I would strongly recommend having a look at those posts and serve your HTML file(s) through FastAPI, which is pretty straightforward, instead of adding null
to the origins
.