A CORS error between an Angular application and an ASP.NET Core API can look like a frontend problem even when the
browser successfully reached the server. The console might say that a request was blocked by CORS policy, that the
Access-Control-Allow-Origin header is missing, or that a preflight request failed. Those messages are useful,
but they do not always tell you which part of the request chain is actually wrong.
The fastest way to fix CORS is to stop treating it as one generic error. Identify the two origins involved, inspect the
browser request, determine whether an OPTIONS preflight is failing, and verify that the API—not Angular—is
returning the correct CORS headers. This guide walks through that process for a typical Angular frontend and ASP.NET
Core API.
What CORS Is Actually Protecting
Browsers apply the same-origin policy to JavaScript running on a page. Two URLs are the same origin only when their scheme, host, and port match. These development URLs are therefore different origins:
Angular: https://localhost:4200
API: https://localhost:7194
Even though both use localhost, the ports differ. The browser requires the API to state that the Angular
origin may read the response. CORS is the HTTP-header mechanism that lets the server make that decision.
CORS is enforced by the browser, but permission comes from the server. You normally fix a CORS error in the API,
reverse proxy, or hosting configuration—not by adding an Access-Control-Allow-Origin request header in Angular.
Step 1: Confirm the Exact Frontend and API Origins
Write down the exact origin of the page and API, including protocol and port. A common mistake is allowing
http://localhost:4200 while Angular actually runs at https://localhost:4200, or allowing a
production hostname without the subdomain the browser really uses.
In ASP.NET Core, WithOrigins expects an origin, not a path:
.WithOrigins("https://localhost:4200")
not:
.WithOrigins("https://localhost:4200/api")
If development, staging, and production all have legitimate frontend origins, list them deliberately through the appropriate environment configuration rather than opening the API to every origin.
Step 2: Inspect the Browser Network Tab Before Guessing
Open DevTools, select the Network tab, reproduce the problem, and look for the API call plus any
OPTIONS request immediately before it. The console summarizes the failure; the network details show what
actually happened.
- Request URL: Is Angular calling the API host you intended?
- Status code: Did the request receive 200, 401, 404, 500, or another response?
- Method: Is it GET, POST, PUT, PATCH, DELETE, or OPTIONS?
- Origin header: What exact origin did the browser send?
- Response headers: Is
Access-Control-Allow-Originpresent and correct?
A server exception, authentication redirect, proxy failure, or wrong URL can surface as a CORS-looking error when the error response does not contain the expected CORS headers.
Step 3: Configure a Named CORS Policy in ASP.NET Core
A clear named policy makes the intended frontend origins easy to review:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddCors(options =>
{
options.AddPolicy("Frontend", policy =>
{
policy
.WithOrigins(
"https://localhost:4200",
"https://app.example.com")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
var app = builder.Build();
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors("Frontend");
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
Registering CORS with AddCors is only half the configuration. The application must also apply the policy.
When explicit routing middleware is present, CORS should run after routing and before authorization so it can evaluate
the selected endpoint and attach the correct response headers.
Step 4: Understand Preflight Requests
Some cross-origin requests require a browser preflight. The browser sends an OPTIONS request first, asking
whether the intended origin, method, and headers are allowed. If the preflight fails, the browser never sends the real
POST, PUT, PATCH, or DELETE request.
OPTIONS https://localhost:7194/api/orders
You normally should not add a special [HttpOptions] action simply to satisfy CORS. Correctly configured CORS
middleware handles the preflight. If OPTIONS returns 404, 405, 401, or is redirected before CORS handles it, inspect
middleware order, authentication rules, hosting configuration, and any reverse proxy in front of the API.
Step 5: Handle Cookies and Credentials Correctly
Cookie-based authentication changes the rules. Angular must opt in to sending credentials:
this.http.get<User>(`${apiUrl}/me`, {
withCredentials: true
});
The API must allow credentials for an explicit origin:
policy
.WithOrigins("https://app.example.com")
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();
Do not combine a wildcard origin with credentialed cross-origin requests. If the application needs cookies across origins, allow only the frontend origins that should actually receive authenticated responses.
Step 6: Use an Angular Development Proxy When It Helps
Angular's development server can proxy API paths to ASP.NET Core. The browser talks to the Angular development origin, while the dev server forwards the request to the backend. This can simplify local development without changing the production architecture.
Create src/proxy.conf.json:
{
"/api/**": {
"target": "https://localhost:7194",
"secure": false
}
}
Then point the Angular serve target to the proxy configuration:
"serve": {
"options": {
"proxyConfig": "src/proxy.conf.json"
}
}
Angular can now call a relative URL such as /api/orders. Treat secure: false as a local-development
convenience for development certificates, not as a production TLS strategy.
Step 7: Check Whether the API Is Failing Before CORS Can Help
If the API throws an exception or a hosting layer rejects the request before ASP.NET Core handles it, the browser may report a missing CORS header even though the real root cause is the server failure. Test the endpoint outside the browser with curl or another API client:
curl -i https://localhost:7194/api/orders
Command-line clients do not enforce browser CORS rules. If curl gets a 500, fix the server exception first. If the API works outside the browser but the browser preflight fails, focus on the CORS path.
Common CORS Fixes That Usually Make Things Worse
Using AllowAnyOrigin Everywhere
AllowAnyOrigin() can be appropriate for a genuinely public, unauthenticated resource, but it should not be
the default response to every CORS error. Explicit origins make an application API's access boundary easier to
understand and review.
Setting Access-Control-Allow-Origin in Angular
Access-Control-Allow-Origin is a response header. The server sends it to the browser. Adding it to an Angular
request does not grant Angular permission to read the response.
Disabling Browser Security or Installing a CORS Extension
A browser extension can hide the symptom on one developer machine while leaving the application broken for users. It also stops you from testing the same security boundary production browsers enforce.
Using no-cors Mode
Fetch mode: 'no-cors' does not turn a protected API request into a normal readable JSON response. It produces
an opaque response with major restrictions, so it is not a solution for a frontend that needs API data.
Why Localhost Works but Production Fails
Compare the deployed frontend origin with the one in your policy. Check the final public URL after custom domains,
redirects, CDN rules, and HTTPS enforcement. https://www.example.com and https://example.com are
different origins.
Also identify which layer owns CORS. Azure App Service, IIS, an API gateway, a reverse proxy, and ASP.NET Core can all affect the final response. Multiple overlapping CORS configurations are harder to reason about than one clearly owned policy.
A Practical CORS Debugging Checklist
- Confirm the exact frontend origin: scheme, host, and port.
- Confirm the exact API URL Angular is calling.
- Inspect the Network tab, not only the console message.
- Check whether an OPTIONS preflight occurs and what status it returns.
- Verify the response contains the expected
Access-Control-Allow-Originvalue. - Confirm both
AddCorsand the applied policy are present. - Run CORS in the correct middleware order.
- If cookies are used, enable credentials on both sides and use explicit origins.
- Test the API outside the browser to uncover server errors hidden behind a CORS symptom.
- Re-check production redirects, proxies, custom domains, and hosting-level CORS settings.
Frequently Asked Questions
Why does GET work while POST fails?
The POST may trigger a preflight that the GET does not. Inspect the OPTIONS request and confirm that the requested method and headers are allowed.
Why do I see a CORS error and a 500 at the same time?
The 500 may be the root cause. Read the API logs and fix the server exception first, then verify the final response includes the expected CORS headers.
Do I need CORS if Angular and the API use the same public origin?
No. If the browser accesses both through the same scheme, host, and port, the request is same-origin. A reverse proxy that exposes the SPA and API under one public origin can therefore simplify production hosting.
Conclusion
Most Angular and ASP.NET Core CORS problems become straightforward once you trace the request instead of changing settings at random. Confirm the origins, inspect preflight behavior, configure the server policy explicitly, put the middleware in the right place, and separate genuine API failures from browser enforcement.
The goal is not to turn CORS off. The goal is to make the browser boundary match your architecture so only the frontend origins that should call the API receive permission to do so.



