DEV Community

Cover image for Fixing CORS Errors in ASP.NET Core APIs (The Real Reasons)
alinabi19
alinabi19

Posted on

Fixing CORS Errors in ASP.NET Core APIs (The Real Reasons)

If you've worked on APIs for a while, you've probably run into this situation.

Your frontend calls your ASP.NET Core API.

Everything looks correct.

But the browser console suddenly throws this error:

Access to fetch at 'https://api.example.com' from origin 'http://localhost:3000' has been blocked by CORS policy
Enter fullscreen mode Exit fullscreen mode

So you try the exact same request in Postman.

It works perfectly.

Now you're confused.

You check the API.
You check the frontend.
Eventually you start adding random CORS settings hoping something finally works.

Before long, your Program.cs starts looking like a CORS experiment lab.

Almost every backend developer hits this problem at some point.

What makes CORS errors frustrating is that:

  • They only appear in browsers
  • API testing tools like Postman work fine
  • Small configuration mistakes can break everything
  • Middleware order matters in ASP.NET Core

After debugging this issue across multiple APIs, the same root causes show up again and again. Let’s walk through what’s actually happening and how to fix it properly.

What CORS Actually Is (In Simple Terms)

CORS stands for Cross-Origin Resource Sharing.

Browsers enforce a security rule called the Same-Origin Policy.

It means a web page can normally only call APIs from the same origin.

An origin is defined as:

Protocol + Domain + Port
Enter fullscreen mode Exit fullscreen mode

For example:

http://localhost:3000
https://api.myapp.com
https://app.myapp.com
Enter fullscreen mode Exit fullscreen mode

Even small differences create a different origin.

Example:

http://localhost:3000
http://localhost:5000
Enter fullscreen mode Exit fullscreen mode

Same machine, different port - still considered cross-origin.

When a frontend application calls an API on another origin, the browser checks whether the API explicitly allows it.

If the response doesn't include the correct CORS headers, the browser blocks the request.

Important point many developers miss:

Your API is usually not rejecting the request.
The browser is refusing to expose the response.

This is also why the request works in Postman - Postman doesn't enforce browser security rules.

Why CORS Errors Happen in ASP.NET Core APIs

After debugging CORS issues in several projects, these are the most common causes.

Missing CORS middleware
CORS support was never enabled in the API.

Wrong middleware order
CORS middleware must run before endpoints execute.

Incorrect origin configuration
The frontend origin isn't included in allowed origins.

Preflight request failure
Browsers sometimes send an OPTIONS request before the real request.

If this fails, the real request never happens.

Credential configuration mistakes
Using cookies or authorization headers incorrectly.

Using AllowAnyOrigin() with credentials
Browsers block this combination for security reasons.

Step 1: The Correct Way to Enable CORS in ASP.NET Core

CORS configuration starts in Program.cs.

Register the CORS policy

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy("FrontendPolicy", policy =>
    {
        policy.WithOrigins("http://localhost:3000")
              .AllowAnyHeader()
              .AllowAnyMethod();
    });
});
Enter fullscreen mode Exit fullscreen mode

This creates a named CORS policy.

Enable the middleware

var app = builder.Build();

app.UseCors("FrontendPolicy");

app.MapControllers();

app.Run();
Enter fullscreen mode Exit fullscreen mode

Now requests from http://localhost:3000 will be allowed.

A common mistake is registering CORS but forgetting to enable the middleware.

Step 2: Understanding Preflight Requests (OPTIONS)

Sometimes browsers send a preflight request before the real request.

Example:

OPTIONS /api/orders
Enter fullscreen mode Exit fullscreen mode

This usually happens when:

The request uses custom headers

The request method is PUT, PATCH, or DELETE

Credentials or authorization headers are used

The browser is essentially asking:

"Is it okay if I send this request?"

If the server doesn't respond with the correct CORS headers, the browser blocks the request before the real API call even happens.

The good news is that ASP.NET Core handles preflight requests automatically when the CORS middleware is configured correctly.

You normally don't need to manually implement OPTIONS endpoints.

Step 3: The Most Common CORS Configuration Mistakes

Mistake 1: Using AllowAnyOrigin() With Credentials

This is extremely common.

Example:

policy.AllowAnyOrigin()
      .AllowCredentials();
Enter fullscreen mode Exit fullscreen mode

This will not work.

Browsers block this configuration because allowing credentials from any origin is a security risk.

Correct approach:

policy.WithOrigins("https://app.example.com")
      .AllowCredentials()
      .AllowAnyHeader()
      .AllowAnyMethod();
Enter fullscreen mode Exit fullscreen mode

Always specify explicit origins when credentials are involved.

Mistake 2: Forgetting to Call UseCors()

Developers often configure CORS but forget to enable the middleware.

Wrong:

builder.Services.AddCors();
Enter fullscreen mode Exit fullscreen mode

Correct:

app.UseCors("FrontendPolicy");
Enter fullscreen mode Exit fullscreen mode

Without the middleware, the policy never runs.

Mistake 3: Wrong Middleware Order

Middleware order matters in ASP.NET Core.

Correct order:

app.UseRouting();

app.UseCors("FrontendPolicy");

app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();
Enter fullscreen mode Exit fullscreen mode

If CORS runs after endpoints, it won't apply to the response.

Step 4: Handling CORS for Frontend Frameworks

During development, frontend frameworks usually run on different ports.

Examples:

React  → http://localhost:3000
Vite   → http://localhost:5173
Angular → http://localhost:4200
Enter fullscreen mode Exit fullscreen mode

Your CORS policy must allow these origins.

Example:

policy.WithOrigins(
    "http://localhost:3000",
    "http://localhost:5173",
    "http://localhost:4200"
)
.AllowAnyHeader()
.AllowAnyMethod();
Enter fullscreen mode Exit fullscreen mode

For production environments, you should only allow trusted domains.

Example:

https://app.mycompany.com
Enter fullscreen mode Exit fullscreen mode

Avoid using AllowAnyOrigin() in production APIs.

Step 5: Debugging CORS Errors Like a Pro

When a CORS error appears, guessing usually wastes time. It's better to check a few things first.

1. Check the Browser Console
Look for errors like:

No 'Access-Control-Allow-Origin' header present
Enter fullscreen mode Exit fullscreen mode

This means the response didn't include the required CORS headers.

2. Inspect the Network Tab
Open DevTools and inspect the OPTIONS request.

If the preflight request fails, the real request will never be sent.

3. Compare Browser vs Postman
If Postman works but the browser fails, it's almost always a CORS issue.

4. Check Response Headers
You can also test the API response headers:

curl -I https://api.example.com
Enter fullscreen mode Exit fullscreen mode

Look for:

Access-Control-Allow-Origin
Enter fullscreen mode Exit fullscreen mode

If it's missing, the browser will block the request.

Step 6: Production Best Practices

A few simple practices make CORS configuration easier to manage in real systems.

Avoid Hardcoding Origins

Instead, load them from configuration.

Example:

var allowedOrigins = builder.Configuration
    .GetSection("Cors:AllowedOrigins")
    .Get<string[]>() ?? Array.Empty<string>();

policy.WithOrigins(allowedOrigins)
      .AllowAnyHeader()
      .AllowAnyMethod();
Enter fullscreen mode Exit fullscreen mode

Configuration example:

"Cors": {
  "AllowedOrigins": [
    "http://localhost:3000",
    "https://app.mycompany.com"
  ]
}
Enter fullscreen mode Exit fullscreen mode

This keeps deployments clean across development, staging, and production.

Be Aware of Reverse Proxies

In production environments your API may sit behind:

  • Nginx
  • Cloudflare
  • Azure Application Gateway
  • Kubernetes ingress

Sometimes these proxies strip or override headers, which can make CORS appear broken even when the API is configured correctly.

If CORS works locally but fails in production, checking the proxy configuration is often the next step.

Common Pitfall

One subtle issue happens when the frontend port changes.

Example:

Frontend running on:

localhost:5173
Enter fullscreen mode Exit fullscreen mode

But the API only allows:

localhost:3000
Enter fullscreen mode Exit fullscreen mode

Different port = different origin.

Even though it's the same machine, the browser treats it as cross-origin.

Quick CORS Debugging Checklist

Problem Cause Fix
Browser CORS error Missing middleware Add AddCors() and UseCors()
Preflight request fails OPTIONS blocked Enable CORS policy
Credentials error Using AllowAnyOrigin() Specify allowed origins
Works in Postman only Browser enforcing CORS Configure proper headers
Production requests blocked Missing frontend domain Add production origin

Final Thoughts

CORS errors can feel confusing at first because the problem usually shows up far away from the real cause.

The key thing to remember is this:

Browsers enforce CORS. Your API usually doesn't.

Most issues come down to a few predictable causes:

  • Missing CORS middleware
  • Wrong middleware order
  • Incorrect origin configuration
  • Preflight request failures

Once you understand how browsers handle cross-origin requests and how ASP.NET Core middleware works, debugging CORS becomes much more straightforward.

And if you've ever spent hours chasing a CORS error before a deployment, you're definitely not alone.

Top comments (0)