What CORS Actually Protects Against
CORS is a browser-enforced security mechanism, not a server-side firewall — it exists because browsers, by default, block JavaScript running on one origin (scheme + host + port) from reading responses from a different origin, to prevent a malicious site from silently using a logged-in user's cookies to read data from another site (like their bank). The server opts specific origins into cross-origin access by returning Access-Control-Allow-Origin and related headers; the browser, not your API, is the one that actually enforces the restriction by blocking the JavaScript from accessing the response if the headers don't match.
Cricket analogy: CORS is like a stadium's away-team dressing room policy — the browser is the security guard who, by default, won't let a visiting team's staff (a foreign origin's script) into the home dressing room unless the home ground explicitly issues them a pass (Access-Control-Allow-Origin).
Configuring the CORS Middleware
You register CORS with builder.Services.AddCors(options => options.AddPolicy("AllowFrontend", policy => policy.WithOrigins("https://app.example.com").AllowAnyMethod().AllowAnyHeader())), then apply it with app.UseCors("AllowFrontend") placed after UseRouting and before UseAuthorization in the middleware pipeline. Policies can be applied globally via app.UseCors() with a default policy, or scoped per-endpoint with [EnableCors("PolicyName")] and [DisableCors] for exceptions, and you can allow credentials (cookies, Authorization headers) with AllowCredentials(), but only in combination with explicitly listed origins — never with AllowAnyOrigin().
Cricket analogy: Defining a named CORS policy like 'AllowFrontend' is like a ground curator issuing a specific access list naming exactly which broadcast trucks (origins) can plug into the stadium's feed, rather than leaving the gate open to any truck that shows up.
Preflight Requests
For 'non-simple' requests — those using methods other than GET/HEAD/POST, or with custom headers like Authorization or Content-Type: application/json — the browser first sends an OPTIONS preflight request asking the server which methods and headers are allowed for that origin, before sending the actual request. ASP.NET Core's CORS middleware automatically intercepts and responds to these OPTIONS requests based on the matching policy, returning 204 with Access-Control-Allow-Methods and Access-Control-Allow-Headers; if the actual request's method or headers aren't covered by the policy, the browser blocks the real request from ever being sent.
Cricket analogy: A preflight OPTIONS request is like a team manager calling the match referee before the game to confirm which substitutions and equipment are allowed, so nobody wastes time attempting something that will be disallowed on the field.
// Program.cs
builder.Services.AddCors(options =>
{
options.AddPolicy("AllowFrontend", policy =>
{
policy.WithOrigins("https://app.example.com", "https://staging.example.com")
.AllowAnyMethod()
.WithHeaders("Content-Type", "Authorization")
.AllowCredentials();
});
});
var app = builder.Build();
app.UseRouting();
app.UseCors("AllowFrontend");
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
// A single endpoint override
[EnableCors("AllowFrontend")]
[HttpGet("public-stats")]
public IActionResult GetPublicStats() => Ok(_statsService.GetSummary());Never combine .AllowAnyOrigin() with .AllowCredentials() — ASP.NET Core will throw an exception at startup because it's a well-known security hole: it would let any website silently make authenticated, cookie-carrying requests to your API on behalf of a logged-in user.
CORS only protects browser-based JavaScript callers. It does nothing to stop server-to-server requests, curl, Postman, or mobile apps, since those clients don't enforce the same-origin policy at all — CORS is not a substitute for authentication and authorization.
- CORS is enforced by the browser, not the server — the API just supplies headers telling the browser what to allow.
- AddCors with named policies configures allowed origins, methods, and headers; UseCors applies the policy in the pipeline.
- UseCors must be placed after UseRouting and before UseAuthorization for endpoint-specific policies to resolve correctly.
- Non-simple requests trigger a browser-issued OPTIONS preflight that the CORS middleware answers automatically.
- AllowCredentials() requires explicitly listed origins and can never be combined with AllowAnyOrigin().
- [EnableCors]/[DisableCors] let you override the default policy for specific controllers or actions.
- CORS does not protect against non-browser clients — it must be paired with real authentication and authorization.
Practice what you learned
1. Who actually enforces the CORS restriction when a cross-origin request's headers don't match the server's policy?
2. What triggers a browser to send a preflight OPTIONS request before the real one?
3. Why does ASP.NET Core throw an exception if you combine AllowAnyOrigin() with AllowCredentials()?
4. Where must app.UseCors() be placed relative to UseAuthorization() for a policy to apply correctly?
5. Does CORS provide any protection against a non-browser client like a curl script directly calling your API?
Was this page helpful?
You May Also Like
Securing APIs: Best Practices
A practical checklist of defense-in-depth techniques for hardening ASP.NET Core Web APIs beyond basic authentication and authorization.
JWT Bearer Authentication
Understand how to secure ASP.NET Core Web APIs with stateless JSON Web Tokens issued and validated via the JWT bearer scheme.
Authorization Policies and Roles
Learn how ASP.NET Core moves beyond simple role checks into flexible, claims-based authorization policies for fine-grained access control.
Related Reading
Related Study Notes in Microsoft Technologies
Browse all study notesWindows 10 / UWP Development Study Notes
.NET · 30 topics
Microsoft TechnologiesWindows Batch Scripting Study Notes
Batch · 30 topics
Microsoft TechnologiesMFC (Microsoft Foundation Classes) Study Notes
C++ · 30 topics
Microsoft TechnologiesSilverlight Study Notes
.NET · 30 topics
Microsoft TechnologiesXAML Study Notes
.NET · 30 topics
Microsoft TechnologiesWPF (Windows Presentation Foundation) Study Notes
.NET · 30 topics