CORS & Cross-Origin Resource Sharing

15 questions found

What is CORS, and why do browsers enforce it?

Beginner
CORS (Cross-Origin Resource Sharing) is a browser security mechanism that restricts web pages from making requests to a different origin (different scheme, domain, or port) than the one that served the page, unless the target server explicitly permits it via response headers. Browsers enforce this to prevent malicious sites from silently making authenticated requests to other sites on a user's behalf using the user's existing cookies/credentials -- it's a client-side (browser) enforced policy, not a server-side security boundary.
// Page served from https://myapp.com trying to call https://api.otherapp.com
fetch('https://api.otherapp.com/data')
  .then(r => r.json());
// Blocked by the browser unless api.otherapp.com's response includes
// Access-Control-Allow-Origin: https://myapp.com (or *)
Real-world example A single-page app hosted at app.mycompany.com calling an API at api.mycompany.com (different subdomain = different origin) needs the API to explicitly configure CORS to allow requests from app.mycompany.com's origin.

Common follow-ups: What exactly counts as a different 'origin' (scheme, host, port)?;Why is CORS enforced by the browser rather than the server itself?

ASP.NET Core Middleware & Request Pipeline;RESTful Web APIs & Controllers

How do you configure a CORS policy in ASP.NET Core to allow requests from specific origins?

Intermediate
Register a named CORS policy via AddCors specifying allowed origins, methods, and headers, then apply it either globally with UseCors(policyName) in the middleware pipeline or per-endpoint/controller with the [EnableCors] attribute -- the policy must be registered before UseAuthorization and typically right after UseRouting in the pipeline order.
builder.Services.AddCors(options => {
    options.AddPolicy("AllowFrontend", policy => {
        policy.WithOrigins("https://app.mycompany.com")
              .AllowAnyMethod()
              .AllowAnyHeader();
    });
});

app.UseCors("AllowFrontend");  // after UseRouting, before UseAuthorization
Real-world example A public API explicitly whitelists only its known frontend origin (https://app.mycompany.com) rather than using a wildcard, ensuring only that specific frontend can make cross-origin requests with credentials.

Common follow-ups: Why must UseCors be positioned specifically between UseRouting and UseAuthorization?;How do you apply different CORS policies to different controllers?

ASP.NET Core Middleware & Request Pipeline;Authentication & Authorization (Identity JWT OAuth)

What is a CORS preflight request, and when does the browser send one automatically?

Advanced
For 'non-simple' requests (using methods other than GET/HEAD/POST, custom headers, or a Content-Type other than a few basic ones), the browser automatically sends an OPTIONS preflight request before the actual request, asking the server 'are you willing to accept this cross-origin request?' via Access-Control-Request-Method and Access-Control-Request-Headers headers -- the server must respond with matching Access-Control-Allow-* headers, and only if the preflight succeeds does the browser send the actual request.
// Browser automatically sends this BEFORE a PUT request with a custom header:
// OPTIONS /api/products/5 HTTP/1.1
// Access-Control-Request-Method: PUT
// Access-Control-Request-Headers: X-Custom-Header

// Server must respond with:
// Access-Control-Allow-Methods: PUT
// Access-Control-Allow-Headers: X-Custom-Header
Real-world example A team debugging why their PUT requests with a custom Authorization-like header mysteriously fail cross-origin discovers the API never explicitly allows that custom header in its CORS policy, causing the preflight OPTIONS request to fail silently before the real request is ever sent.

Common follow-ups: What HTTP methods/headers count as 'simple' and avoid triggering preflight?;How can you cache preflight results to avoid repeating them on every request?

RESTful Web APIs & Controllers;ASP.NET Core Middleware & Request Pipeline

What does AllowCredentials() do in a CORS policy, and why can't it be combined with a wildcard origin?

Intermediate
AllowCredentials() permits cross-origin requests to include credentials (cookies, HTTP authentication, client certificates), required for cookie-based authentication to work across origins. The CORS specification explicitly disallows combining AllowCredentials with a wildcard (*) origin as a security measure -- if credentialed requests were allowed from literally any origin, it would defeat CORS's core purpose of restricting which sites can make authenticated requests on a user's behalf, so you must specify exact allowed origins when using credentials.
// This configuration throws an exception at runtime:
// policy.AllowAnyOrigin().AllowCredentials();  // INVALID combination

// Correct: specific origins required with credentials
policy.WithOrigins("https://app.mycompany.com")
      .AllowCredentials()
      .AllowAnyHeader()
      .AllowAnyMethod();
Real-world example A team's cookie-based authentication mysteriously stopped working cross-origin after someone changed a CORS policy from specific origins to AllowAnyOrigin(), not realizing this silently disables credentialed requests entirely due to the spec-level incompatibility.

Common follow-ups: Why is combining wildcard origins with credentials considered a security risk?;How do JWT bearer tokens sidestep this particular CORS/credentials constraint?

Authentication & Authorization (Identity JWT OAuth);RESTful Web APIs & Controllers

How do you apply different CORS policies to different endpoints or controllers within the same application?

Advanced
Register multiple named policies with AddCors, then apply a specific one to individual controllers or actions using [EnableCors("PolicyName")], overriding whatever the default/global policy might be -- and use [DisableCors] to explicitly opt an endpoint out of CORS entirely (blocking all cross-origin access to that specific endpoint) regardless of the global configuration.
builder.Services.AddCors(options => {
    options.AddPolicy("PublicApi", p => p.AllowAnyOrigin().WithMethods("GET"));
    options.AddPolicy("AdminApi", p => p.WithOrigins("https://admin.mycompany.com").AllowCredentials());
});

[EnableCors("PublicApi")]
public class ProductsController : ControllerBase { }

[EnableCors("AdminApi")]
public class AdminController : ControllerBase { }
Real-world example A single API exposes both a fully public, read-only product catalog (permissive CORS for any origin) and a sensitive admin management interface (restricted to only the internal admin frontend's origin with credentials), using distinct named CORS policies per controller.

Common follow-ups: What happens if both a global UseCors policy and an [EnableCors] attribute are present?;How would [DisableCors] interact with a permissive global default policy?

Authentication & Authorization (Identity JWT OAuth);ASP.NET Core Middleware & Request Pipeline

Why must UseCors be positioned after UseRouting but before UseAuthorization in the ASP.NET Core middleware pipeline?

Intermediate
UseCors needs routing to have already matched the request to determine which endpoint's specific CORS policy (if using [EnableCors] per-endpoint) applies, so it must come after UseRouting. It must come before UseAuthorization because a CORS preflight OPTIONS request has no authentication credentials and would otherwise be incorrectly rejected by authorization checks before CORS even gets a chance to respond to it -- placing CORS first ensures preflight requests are handled correctly regardless of the endpoint's authorization requirements.
app.UseRouting();        // must be first: matches endpoint metadata
app.UseCors("MyPolicy");  // must be here: needs endpoint match, but before auth
app.UseAuthentication();
app.UseAuthorization();   // preflight OPTIONS requests never reach this far incorrectly
Real-world example A production bug where cross-origin requests to an [Authorize]-protected endpoint always failed with CORS errors (not auth errors) was traced to UseCors being registered after UseAuthorization instead of before, causing preflight requests to be rejected by the authorization check first.

Common follow-ups: What HTTP status does a rejected preflight request typically show in browser dev tools?;How does this ordering interact with endpoint-specific EnableCors attributes?

ASP.NET Core Middleware & Request Pipeline;Authentication & Authorization (Identity JWT OAuth)

What security risks does an overly permissive CORS policy (like AllowAnyOrigin with credentials attempted, or reflecting the Origin header) introduce?

Advanced
While AllowAnyOrigin combined with AllowCredentials is blocked by the spec itself, a common but dangerous workaround some developers implement is dynamically 'reflecting' whatever Origin header the request sends back as the Access-Control-Allow-Origin value (effectively allowing every origin while still technically satisfying the credentials requirement) -- this defeats CORS's entire security purpose, allowing any malicious website to make authenticated cross-origin requests using a logged-in user's cookies, a serious CSRF-adjacent vulnerability.
// DANGEROUS anti-pattern: reflecting any origin defeats CORS's purpose
policy.SetIsOriginAllowed(origin => true)  // allows literally ANY origin
      .AllowCredentials();

// SAFE: explicit allowlist of known, trusted origins only
policy.WithOrigins("https://app.mycompany.com", "https://admin.mycompany.com")
      .AllowCredentials();
Real-world example A security audit flags a CORS configuration using SetIsOriginAllowed(_ => true) combined with AllowCredentials as a critical vulnerability, since it effectively allows any malicious website to make authenticated API calls using a victim's session cookies.

Common follow-ups: How would an attacker actually exploit an overly permissive CORS + credentials configuration?;What's the safe way to support multiple known frontend origins?

Authentication & Authorization (Identity JWT OAuth);Global Exception Handling & Middleware

How do you configure CORS to allow requests only from multiple specific origins, such as both a production and staging frontend?

Intermediate
WithOrigins() accepts multiple origin strings as parameters (or you can call SetIsOriginAllowed with custom logic for more dynamic matching, like allowing any subdomain pattern), letting a single policy explicitly whitelist several known, trusted origins simultaneously without resorting to an insecure wildcard.
builder.Services.AddCors(options => {
    options.AddPolicy("KnownFrontends", policy => {
        policy.WithOrigins(
            "https://app.mycompany.com",
            "https://staging.mycompany.com",
            "http://localhost:3000"  // local dev
        ).AllowAnyMethod().AllowAnyHeader();
    });
});
Real-world example A team maintains one CORS policy listing their production domain, staging domain, and localhost development URL together, so the same API configuration correctly supports developers, QA testers on staging, and real production users simultaneously.

Common follow-ups: Should localhost origins ever be included in a production CORS policy?;How do you manage this origin list across different deployment environments?

CI/CD Publishing & Deployment;Configuration & Options

How does CORS interact with a reverse proxy or API gateway sitting in front of multiple backend microservices?

Advanced
When a browser calls through an API gateway acting as a single origin (e.g., https://api.mycompany.com routing to multiple backend services), CORS only needs to be configured once at the gateway layer since that's the origin the browser actually communicates with -- the backend microservices behind the gateway typically don't need their own CORS configuration since they're never called directly cross-origin by the browser, simplifying CORS management significantly in a microservices architecture.
// Browser only ever talks to the gateway origin:
// fetch('https://api.mycompany.com/orders')  -- gateway handles CORS
// Gateway internally routes to http://orders-service:8080 (no CORS needed here,
// since this is server-to-server, not browser-to-server)
Real-world example A microservices platform configures CORS exactly once at their YARP-based API gateway, eliminating the need to duplicate and maintain consistent CORS policies across dozens of individual backend services that the browser never contacts directly.

Common follow-ups: What CORS considerations remain if a gateway does server-side aggregation calling multiple backends?;How does this simplification break down if some services are exposed directly, bypassing the gateway?

Microservices & Distributed Architecture Patterns;ASP.NET Core Middleware & Request Pipeline

What is the difference between CORS and CSRF (Cross-Site Request Forgery), and how does CORS relate to (but not fully prevent) CSRF?

Intermediate
CSRF exploits the browser's automatic inclusion of credentials (cookies) on requests to any site, tricking a user's browser into making an unwanted authenticated request to a target site from a malicious page, regardless of CORS. CORS actually offers some incidental protection against CSRF for APIs, since a properly restrictive CORS policy prevents a malicious site's JavaScript from reading the response of a cross-origin request (though the request may still fire and take effect server-side) -- but CORS alone is not a complete CSRF defense, since simple form-based CSRF attacks (not requiring the attacker to read the response) can still succeed; dedicated anti-forgery tokens remain necessary for full protection.
// A malicious site can still trigger this request (CSRF), even with strict CORS,
// because a simple form POST doesn't require reading the response:
// <form action="https://bank.com/transfer" method="POST">
//   <input type="hidden" name="amount" value="10000">
// </form>
// CORS prevents the attacker's JS from READING the response, but the transfer may still happen
Real-world example A security review clarifies to the team that their strict CORS policy protects their API from cross-origin JavaScript reading sensitive responses, but doesn't fully protect a cookie-authenticated form-based endpoint from CSRF, which still requires anti-forgery tokens.

Common follow-ups: How do anti-forgery tokens (like ASP.NET Core's built-in ones) provide CSRF protection CORS can't?;Why is SameSite=Strict/Lax cookie configuration also relevant here?

Authentication & Authorization (Identity JWT OAuth);Global Exception Handling & Middleware

Showing 1–10 of 15