Skip to course content
Free FastAPI backend course

FastAPI for AI Backend Development

Unit 10.03: CORS, and what it actually protects

CORS is enforced by the browser, for browsers, and protects nothing else.

What it does and what it does not

An app with an allowed origin, called from an allowed and a disallowed one.

The code shows the header returned in each case.

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.testclient import TestClient

app = FastAPI()
app.add_middleware(CORSMiddleware, allow_origins=["https://app.example.com"],
                   allow_methods=["GET", "POST"], allow_headers=["*"])


@app.get("/data")
def data() -> dict:
    return {"ok": True}


client = TestClient(app)
for origin in ("https://app.example.com", "https://evil.example.com"):
    r = client.get("/data", headers={"Origin": origin})
    allowed = r.headers.get("access-control-allow-origin")
    print(f"{origin:30} -> allow-origin: {allowed}")

print("""
CORS is enforced by the BROWSER, for browser-initiated cross-origin requests.
It stops a page on another origin reading your response.

It stops nothing else. curl, a script and a server ignore it entirely, so CORS
is not an access control -- the API key and the scope check are.
""")

The mechanism is a header telling the *browser* whether a page on another origin may read the response. The request still reached your server in both cases.

curl, a script, a mobile app and another server ignore CORS entirely. So it is not an access control - the API key and the scope check from the previous unit are.

The mistake this prevents

The mistake is setting a permissive CORS policy and considering the API protected, or setting a restrictive one and considering it secured. Neither is true: CORS governs browser reads and nothing else.

Takeaway

CORS controls what a browser lets a page read cross-origin. Every non-browser client ignores it, so it is not an access control.