Cheat SheetsFull-Stack IntegrationCORS

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