has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on
the requested resource. means your ASP.NET Core API answered the request, but without
the header that tells the browser this page may read the answer. Register a CORS policy that
names the page's origin and apply it with UseCors.
In Program.cs, call AddCors with a named policy listing the exact
origin (scheme, host and port, no trailing slash), then app.UseCors("PolicyName").
The JavaScript does not change.
The error
Access to fetch at 'http://127.0.0.1:15601/api/patients' from origin 'http://127.0.0.1:15602' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Failed to load resource: net::ERR_FAILED
Those two lines are the browser console; the page itself showed only
Error: TypeError: Failed to fetch, because the browser keeps the reason from
JavaScript.
The page was served from http://127.0.0.1:15602 and called an API on
http://127.0.0.1:15601. A different port is a different origin.
Why it happens
CORS is enforced by the browser, not by the server. Asking the API the way the browser does,
with an Origin header, shows that it worked fine:
curl.exe -s -i -H 'Origin: http://127.0.0.1:15602' http://127.0.0.1:15601/api/patients
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Date: Fri, 23 Oct 2026 04:39:45 GMT
Server: Kestrel
Transfer-Encoding: chunked
[{"id":1,"name":"Maria Garcia"},{"id":2,"name":"David Chen"}]
A 200 with both patients, and no Access-Control-Allow-Origin header. The browser
gets the same response, sees that it does not name the calling page's origin, and
withholds it from the script. That is the whole mechanism: the request ran on the server,
only the reading was blocked. A request with a custom header such as
Authorization makes the browser send an OPTIONS preflight first;
against this API the preflight got HTTP/1.1 405 Method Not Allowed, because
the route accepts only GET and nothing answers OPTIONS without the CORS
middleware.
The fix
builder.Services.AddCors(options =>
{
options.AddPolicy("ClinicPage", policy =>
policy.WithOrigins("http://127.0.0.1:15604")
.WithMethods("GET"));
});
var app = builder.Build();
app.UseCors("ClinicPage");
The fixed API on port 15603, asked from the fixed page's origin:
curl.exe -s -i -H 'Origin: http://127.0.0.1:15604' http://127.0.0.1:15603/api/patients
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Date: Fri, 23 Oct 2026 04:39:45 GMT
Server: Kestrel
Access-Control-Allow-Origin: http://127.0.0.1:15604
Transfer-Encoding: chunked
The preflight now returns 204 No Content with
Access-Control-Allow-Methods: GET and the same origin header. An origin the
policy does not list still gets a 200 without the header, so only the named page can read
the data.
Order matters in a pipeline that has routing and authorization. Microsoft's CORS page puts
it this way: "The call to UseCors must be placed after UseRouting, but before
UseAuthorization." This minimal API calls neither, so UseCors goes right after
Build(); a test copy with UseCors after MapGet also
sent the header, because minimal API endpoints run at the end of the pipeline.
Two classic mistakes. AllowAnyOrigin() with AllowCredentials() did
not give a bad response, as the documentation suggests; the app refused to start with
System.InvalidOperationException: The CORS protocol does not allow specifying a
wildcard (any) origin and credentials at the same time. List the origins instead. And
WithOrigins("http://127.0.0.1:15604/"), with a trailing slash, started fine but
never matched: the GET and the preflight both came back without
Access-Control-Allow-Origin, which is the original error again.
How it was reproduced
Four empty projects from dotnet new web on .NET SDK 10.0.402 with the ASP.NET
Core 10.0.13 runtime, no packages: an API without CORS on 15601, a static page calling it on
15602, the fixed API on 15603 and its page on 15604, all bound to 127.0.0.1. The server
side was checked with curl.exe 8.21.0, sending the Origin header a
browser would send; the console lines come from a Chromium-based browser opening the page on
15602, and the same browser on the fixed page on 15604 printed no error and showed both
patients.
Frequently asked
- How do I fix No Access-Control-Allow-Origin header in ASP.NET Core?
- Add builder.Services.AddCors with a named policy that lists the calling page's origin in WithOrigins, then call app.UseCors with that policy name. The API then returns Access-Control-Allow-Origin for that origin and the browser lets the script read the response.
- Why does my API work in Postman or curl but not in the browser?
- CORS is enforced only by browsers. The server answers every client the same way; the browser alone checks for Access-Control-Allow-Origin and hides the response from the page when the header is missing.
- Can I use AllowAnyOrigin with AllowCredentials in ASP.NET Core?
- No. On ASP.NET Core 10 the app throws InvalidOperationException at startup saying the CORS protocol does not allow a wildcard origin with credentials. List the allowed origins with WithOrigins instead.
More decoded errors in the Fixes category. For a design that needs no CORS at all, because no browser calls the API directly, see The App Needs a Door: A Thin API Over the Clinic.