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:

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:

  1. Browser checks if request is simple or complex.

  2. For complex requests (PUT, DELETE, custom headers), browser sends a preflight OPTIONS request.

  3. Server must respond with proper CORS headers.

  4. If headers allow the origin, browser sends actual request.

  5. If headers are missing or invalid, browser blocks it.

Example of required response 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:

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

FeatureAllowAnyOriginWithOrigins
Security LevelLowHigh
Suitable for ProductionNoYes
Allows Specific DomainNoYes
Supports CredentialsNoYes
Recommended UsageDevelopment onlyProduction environments

In production systems, always prefer WithOrigins for security.

Handling Preflight OPTIONS Request

Complex requests (PUT, DELETE, Authorization headers) trigger preflight.

Ensure:

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

When NOT to Use Open CORS Policy

Avoid open CORS policies when:

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

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.