CORS — Cheat Sheet
Full-Stack Integration · 2 topics. Download the PDF or the Instagram carousel and share it.
Cheat Sheet · AiCanCode.org
CORS
Full-Stack Integration2 topicsQuick revision reference
1
CORS — What Is Actually Happening
The browser blocks your response because you asked another origin for it. CORS is the server's way of saying that is allowed — which is why no amount of frontend code can fix it.
- ✓An origin is scheme, host and port — a different port is a different origin
- ✓CORS blocks JavaScript from READING a cross-origin response; the request was usually still sent and executed
- ✓POSTing application/json or sending an Authorization header triggers an OPTIONS preflight
- ✓Access-Control-Max-Age caches the preflight — without it every call costs two round trips
- ✓The fix is always on the server, and curl succeeding proves nothing because only browsers enforce CORS
Scheme + host + port, and read vs send
// An origin is scheme + host + PORT. All three must match. https://aicancode.org vs https://api.aicancode.org // different http://localhost:3000 vs http://localhost:8000 // different https://aicancode.org vs http://aicancode.org // different // Why it exists: you are logged into your bank. You visit a hostile // page. Without the same-origin policy, its JavaScript could call // the bank's API with your cookies attached and READ the response. // The policy stops the reading. // Note what it does NOT stop: the request being SENT. A cross-origin // form POST still reaches the server with cookies attached — that is // CSRF, and it is a separate problem with a separate fix. // Not subject to CORS at all — these are cross-origin by design: <img src="https://other.com/a.png"> <script src="https://cdn.com/lib.js"> <form action="https://other.com/submit" method="post"> // Subject to CORS: fetch, XMLHttpRequest, and anything else that // lets JavaScript READ the response.
2
Configuring CORS Correctly
Allow the origins you actually deploy, never a wildcard with credentials, and know why the same config behaves differently in production.
- ✓Allowed origins belong in configuration, listing every real domain including www and preview URLs
- ✓A wildcard origin with credentials is forbidden by the spec — echo a validated origin and set Vary: Origin
- ✓Never reflect an unvalidated Origin header; that is a wildcard with extra steps and a real vulnerability
- ✓A 500 raised before the CORS middleware produces a CORS error that is really a server crash — check the logs first
- ✓Proxying the API through the frontend origin removes CORS entirely and makes cookies first-party
Origins from configuration, not constants
# FastAPI
from fastapi.middleware.cors import CORSMiddleware
app.add_middleware(
CORSMiddleware,
allow_origins=settings.ALLOWED_ORIGINS, # from env, never hardcoded
allow_credentials=True, # required for cookies
allow_methods=["GET", "POST", "PATCH", "DELETE", "OPTIONS"],
allow_headers=["Content-Type", "Authorization", "X-Request-Id"],
expose_headers=["X-Request-Id", "X-Total-Count"],
max_age=86400,
)
# ALLOWED_ORIGINS=https://aicancode.org,https://www.aicancode.org,
# https://aicancode-git-preview.vercel.app
// Spring Boot
@Bean
CorsConfigurationSource corsConfigurationSource() {
var c = new CorsConfiguration();
c.setAllowedOrigins(List.of(env.getProperty("app.origins").split(",")));
c.setAllowCredentials(true);
c.setAllowedHeaders(List.of("Content-Type", "Authorization"));
c.setMaxAge(86400L);
var src = new UrlBasedCorsConfigurationSource();
src.registerCorsConfiguration("/**", c);
return src;
}
// With Spring Security, CORS must be enabled in the filter chain too,
// or the security filter rejects the preflight before CORS runs.Learn this free with Aria, your AI tutor → AiCanCode.org/learn/full-stack