CORS (Cross-Origin Resource Sharing) errors are one of the most common issues developers face when building ASP.NET Core Web APIs that are consumed by frontend applications such as Angular, React, Vue, or mobile clients. In production environments, improper CORS configuration can block legitimate requests, expose security vulnerabilities, or break integration between microservices. This guide explains what CORS is, why CORS errors occur, how the browser enforces it, and how to fix CORS issues in ASP.NET Core using secure and production-ready configurations.
What is CORS?
CORS (Cross-Origin Resource Sharing) is a browser security mechanism that restricts web pages from making requests to a different domain, protocol, or port than the one from which the page was served.
Origin consists of three components:
If any of these differ, the request is considered cross-origin.
Real-world analogy:
Think of CORS as a security guard at an office building. Even if someone has valid documents (HTTP request), the guard checks whether they are allowed to enter from another company (different origin). If not approved, access is denied.
Since the domains differ, the browser blocks the request unless the API explicitly allows it.
Why Does CORS Error Occur?
CORS errors occur because:
The server does not send the Access-Control-Allow-Origin header
The origin is not allowed in CORS policy
Credentials are sent but not allowed
Preflight OPTIONS request fails
HTTP and HTTPS mismatch
Important:
CORS is enforced by the browser, not by ASP.NET Core. Tools like Postman do not show CORS errors because they do not enforce browser security rules.
How CORS Works Internally
When a browser makes a cross-origin request:
Browser checks if request is simple or complex.
For complex requests (PUT, DELETE, custom headers), browser sends a preflight OPTIONS request.
Server must respond with proper CORS headers.
If headers allow the origin, browser sends actual request.
If headers are missing or invalid, browser blocks it.
Example of required response headers:
Access-Control-Allow-Origin
Access-Control-Allow-Methods
Access-Control-Allow-Headers
If these are missing, you will see errors like:
"Access to fetch at 'API_URL' from origin 'FRONTEND_URL' has been blocked by CORS policy."
Step-by-Step: Fix CORS Error in ASP.NET Core
Step 1: Configure CORS in Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy("AllowFrontend",
policy =>
{
policy.WithOrigins("https://myfrontend.com")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
builder.Services.AddControllers();
var app = builder.Build();
app.UseCors("AllowFrontend");
app.MapControllers();
app.Run();
Explanation:
AddCors registers CORS services.
AddPolicy defines allowed origins.
UseCors enables middleware.
WithOrigins restricts access to specific domain.
Step 2: Allow Multiple Origins (If Required)
policy.WithOrigins(
"https://myfrontend.com",
"https://admin.myfrontend.com");
Step 3: Allow Credentials (If Using Authentication)
If your API uses cookies or authentication tokens:
policy.WithOrigins("https://myfrontend.com")
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();
Important:
When AllowCredentials() is used, you cannot use AllowAnyOrigin().
Difference Between AllowAnyOrigin and WithOrigins
| Feature | AllowAnyOrigin | WithOrigins |
|---|
| Security Level | Low | High |
| Suitable for Production | No | Yes |
| Allows Specific Domain | No | Yes |
| Supports Credentials | No | Yes |
| Recommended Usage | Development only | Production environments |
In production systems, always prefer WithOrigins for security.
Handling Preflight OPTIONS Request
Complex requests (PUT, DELETE, Authorization headers) trigger preflight.
Ensure:
UseCors is placed before MapControllers
OPTIONS method is not blocked by middleware
Firewall or reverse proxy is not blocking OPTIONS
If using IIS or Nginx, verify configuration allows OPTIONS requests.
Real Production Scenario
Imagine an ASP.NET Core API deployed on Azure App Service and a React frontend hosted on Azure Static Web Apps. Everything works locally, but after deployment, login fails.
Reason:
The backend did not allow the frontend production URL in CORS policy.
Fix:
Add production domain to WithOrigins() and redeploy.
Result:
Authentication works correctly and browser stops blocking requests.
Common Mistakes Developers Make
Using AllowAnyOrigin in production
Forgetting to enable UseCors middleware
Placing UseCors after MapControllers
Not handling HTTPS mismatch
Forgetting to allow credentials
Ignoring preflight request failures
When NOT to Use Open CORS Policy
Avoid open CORS policies when:
API handles sensitive data
Authentication is involved
Application is public-facing
Open CORS can expose your API to abuse and cross-site attacks.
Advanced Scenario: Dynamic CORS Policy
If your application supports multi-tenant domains, you can dynamically validate origins:
policy.SetIsOriginAllowed(origin =>
{
return origin.EndsWith(".mydomain.com");
});
This allows subdomains while maintaining security control.
Best Practices for CORS in ASP.NET Core
Restrict origins in production
Use HTTPS everywhere
Monitor preflight failures
Avoid wildcard origins
Test CORS after deployment
Combine with proper authentication and authorization
Summary
Fixing CORS errors in ASP.NET Core requires understanding that CORS is a browser-enforced security mechanism that blocks cross-origin requests unless explicitly allowed by the server. By properly configuring CORS policies using AddCors, restricting allowed origins with WithOrigins, enabling credentials securely, and ensuring middleware order is correct, developers can resolve cross-origin issues without compromising security. Instead of using open policies like AllowAnyOrigin in production, it is essential to implement restricted and well-defined CORS configurations that protect APIs while enabling seamless communication between frontend and backend applications.