🚦 CORS in ASP.NET: Why your API “works in Postman” but fails in the browser
If your frontend gets:
❌ Blocked by CORS policy
…your API is fine. The browser is blocking the call.
✅ What CORS actually is
CORS (Cross-Origin Resource Sharing) is a browser security rule (same-origin policy).
It decides whether https://app.com can call https://api.com.
Postman isn’t a browser → it doesn’t enforce CORS → so it “works”.
🧠 The mental model
An “origin” is: scheme + host + port
So these are different origins:
- https://localhost:5173
- https://localhost:5001
And that triggers CORS.
⚡ Preflight (the “OPTIONS” request)
For “non-simple” requests (custom headers, PUT, DELETE, Authorization, JSON content-types…), the browser sends:
OPTIONS /endpoint(preflight)- If allowed → the real request happens
If your API doesn’t respond correctly to OPTIONS, you’ll fail before your controller is hit.
✅ The correct setup (ASP.NET Core)
Rule #1: Configure CORS once, apply it early, and keep it explicit.
var builder = WebApplication.CreateBuilder(args); builder.Services.AddCors(options => { options.AddPolicy("Frontend", policy => policy.WithOrigins( "https://localhost:5173", "https://app.mycompany.com") .AllowAnyHeader() .AllowAnyMethod() .AllowCredentials() // only if you use cookies ); }); var app = builder.Build(); // Order matters! app.UseHttpsRedirection(); app.UseCors("Frontend"); // ✅ before auth/authorization app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); app.Run();
⚠️ Common mistakes (aka “CORS still not working 😭”)
✅ Using AllowAnyOrigin() together with AllowCredentials() (not allowed)
✅ Calling UseCors() after UseAuthorization() / endpoints
✅ Using WithOrigins("https://app.com/") (trailing slash mismatch)
✅ Forgetting the exact port in local dev
✅ Wildcard subdomains don’t work with WithOrigins()
Use SetIsOriginAllowed(...) if needed.
🔒 Production tips
- Prefer explicit origins (don’t use
AllowAnyOrigin()in prod) - If you use cookies (auth), you’ll also need:
SameSite=None; Secure- HTTPS everywhere
- CORS is not a security boundary for your API. AuthZ still matters.
#dotnet #aspnetcore #webapi #cors #csharp #softwareengineering #backend