AtomLearnAtomLearn
DashboardGoalsPathAchievementsReviewSign In
Web & HTTPNot Started

CORS

Cross-Origin Resource Sharing — why it exists and how to configure it

0%
Knowledge0%
Learn & Drill
Fluency0%
Drill & Speed
Retention0%
Mastery & Review
Confidence0%
All modes
Practice

Free tier: read the explanation here. Upgrade to Pro for Drills, Speed challenges & Mastery badges.

Upgrade
Knowledge
Fluency
Retention

Knowledge Debt detected

You can study this freely — but your score may plateau if these foundations have gaps. The Mastery badge requires them to be solid.

Explanation

CORS (Cross-Origin Resource Sharing) is a browser security mechanism that blocks web pages from making requests to a different domain than the one that served them.

CORS Preflight — browser asks permission before the real requestBrowserAPI Server① OPTIONS /api/data (preflight)Origin: https://app.com · Method: POST② 200 OK (allowed!)Access-Control-Allow-Origin: https://app.com③ POST /api/data (actual request)④ 200 OK { data: … }CORS is enforced by the BROWSER only — server-to-server calls are never blocked by CORS

The Same-Origin Policy:

A script on https://app.com cannot fetch https://api.example.com by default. They are different origins (different domain). This prevents malicious sites from silently making API calls using your logged-in cookies.

When CORS kicks in:

  • Your React app on localhost:3000 calls your Flask API on localhost:5000 → CORS error
  • app.com calls api.app.com → CORS error (different subdomain)
  • app.com calls its own app.com/api → no CORS (same origin)

How it works — the browser preflight:

Browser → OPTIONS /api/users HTTP/1.1 Origin: https://app.com Access-Control-Request-Method: POST Server → 200 OK Access-Control-Allow-Origin: https://app.com Access-Control-Allow-Methods: GET, POST, PUT, DELETE Access-Control-Allow-Headers: Authorization, Content-Type Browser → POST /api/users (actual request, now allowed)

Configuring CORS in Flask:

python from flask import Flask from flask_cors import CORS app = Flask(__name__) # Allow all origins (dev only — dangerous in production) CORS(app) # Restrict to specific origin (production) CORS(app, origins=["https://yourapp.com"]) # Or per-route @app.route("/api/data") @cross_origin(origins="https://yourapp.com") def data(): return {"ok": True}

Access-Control-Allow-Origin: * means anyone can call the API** — only use for truly public APIs.

Examples

CORS in FastAPI

FastAPI CORS configuration — list specific origins in production

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

app = FastAPI()

app.add_middleware(
    CORSMiddleware,
    allow_origins=["https://yourapp.com", "http://localhost:3000"],
    allow_credentials=True,   # allows cookies/auth headers
    allow_methods=["*"],      # GET, POST, PUT, PATCH, DELETE, OPTIONS
    allow_headers=["*"],      # Authorization, Content-Type, etc.
)

Why CORS errors happen in dev

CORS is a browser constraint — server-to-server requests are never blocked by CORS

# Common dev setup that causes CORS errors:
# - React dev server: http://localhost:3000
# - Flask API:        http://localhost:5000
# These are DIFFERENT origins → browser blocks the request

# Fix option 1: Configure CORS on the server (shown above)

# Fix option 2: Proxy in Vite config (vite.config.ts)
# server: {
#   proxy: {
#     '/api': 'http://localhost:5000'
#   }
# }
# Now requests go to localhost:3000/api → proxied to 5000
# Same origin from browser's perspective → no CORS

How well did you understand this?