The Error
Browser console:
Access to fetch at 'https://api.site.com/users' from origin 'https://app.site.com' has been blocked by CORS policy
Quick Fix - 2 Minutes
Add CORS in Program.cs BEFORE UseAuthorization.
builder.Services.AddCors(options =>
{
options.AddPolicy("AllowFrontend", policy =>
{
policy.WithOrigins("https://app.site.com", "http://localhost:3000")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
var app = builder.Build();
app.UseCors("AllowFrontend"); // Must be before UseAuthorization
app.UseAuthorization();
Why This Happens
Browsers block cross-origin requests. If React on localhost:3000 calls API on localhost:7102, API must send Access-Control-Allow-Origin header.
Step-by-Step Debug
- Order matters:
UseCorsbeforeUseAuthorizationandMapControllers - Exact origin:
httpvshttpsand port must match - Check OPTIONS: Preflight request must return CORS headers
Real-World Scenario: CORS Works in Postman, Fails in Browser
#1 dev confusion. Postman gets 200 OK, Chrome gets CORS error:
// Dev Fix: Postman doesn't enforce CORS. Browsers do.
// Preflight OPTIONS request fails because middleware order is wrong.
var app = builder.Build();
// WRONG ORDER - CORS runs after auth. Preflight has no auth token = 401
app.UseAuthorization();
app.UseCors("AllowFrontend"); // Too late
app.MapControllers();
// RIGHT ORDER - CORS runs first, handles OPTIONS preflight
app.UseRouting(); // Dev Fix: .NET 8 needs explicit UseRouting before CORS
app.UseCors("AllowFrontend"); // Returns 200 OK with CORS headers for OPTIONS
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
3 critical fixes for.NET 8:
- UseRouting first: .NET 8 implicit routing still requires
UseRouting()beforeUseCors()when using endpoint routing. - No trailing slash:
https://app.site.com/is different fromhttps://app.site.com. Match exactly. - Credentials: If using cookies/JWT in header, add
.AllowCredentials()AND remove.AllowAnyOrigin(). Use exact origins.
Related Fixes You Should Know
CORS errors usually mean these issues too:
- CORS With Credentials - You added
.AllowCredentials()but kept.AllowAnyOrigin(). Browsers block it. Use.SetIsOriginAllowed(origin => true)for dev only, exact origins for prod. - JWT Signature Validation Failed - CORS works but API returns 401. Token not sent because CORS blocked
Authorizationheader. Add.WithHeaders("Authorization")or.AllowAnyHeader(). - HTTPS Redirect Loop - CORS preflight uses HTTP, gets 307 redirect to HTTPS. Redirect strips CORS headers. Fix HTTPS redirection middleware order.
- SignalR CORS Error - SignalR needs
.AllowCredentials()+ exact origin +.WithExposedHeaders()for long-polling fallback.
FAQ
Q: Why does CORS work in Postman but not Chrome?
CORS is a browser security feature. Postman, curl, mobile apps ignore it. Only browsers check Access-Control-Allow-Origin header. Always test in browser, not Postman.
Q: Can I use .AllowAnyOrigin() in production?
Only for public APIs with no auth. If you use cookies or JWT tokens, browsers require exact origin match when AllowCredentials() is set. AllowAnyOrigin() + credentials = blocked.
Common Scenarios
- Wrong order: 80% of CORS bugs
- AllowAnyOrigin + credentials: Can't use both. Pick exact origins if using cookies
- SignalR: Needs
.AllowCredentials()and exact origin
No comments yet. Be the first to share your thoughts!