How do I resolve a CORS issue in an Ajax POST to ASP.NET Core 6.0 Web API?

I have an ASP.NET website (not a web app) that makes an Ajax POST call using JQuery 2.1.4 to an ASP.NET Core 6.0 Web API.

When I make the call to the method I am getting a CORS error. Yet, when I make a GET Ajax request to a different method in the same controller, the request is successful.

My Ajax POST:

function insertLNItemStorageRequirement() {
  var tempLNStorage = {
    TItem: storageTempReq.t_item,
    TSrq1: storageTempReq.t_srq1,
    TSrq2: storageTempReq.t_srq2,
    TSq27: storageTempReq.t_sq27,
    TStmp: storageTempReq.t_stmp,
    TRcdVers: 0,
    TRefcntd: 0,
    TRefcntu: 0,
  };

  $.ajax({
    type: "POST",
    url: commonAPIURL + "api/LN/InsertItemStorageRequirement",
    data: JSON.stringify(tempLNStorage),
    contentType: "application/json; charset=utf-8",
    //dataType: "json",
    xhrFields: { withCredentials: true },
    success: function (response) {},
    failure: function (response) {
      alert(response.responseText);
    },
    error: function (response) {
      alert(response.responseText);
    },
  });
}

Here is the ASP.NET Core Web API method being called:

[HttpPost("InsertItemStorageRequirement")]
[Produces(typeof(IActionResult))]
public IActionResult InsertItemStorageRequirement([FromBody] Ttccgs016424 itemStorageReq)
{
    Ttccgs016424 newItemStorageReq = _LN.Ttccgs016424s.FirstOrDefault(s => s.TItem == itemStorageReq.TItem);

    if (newItemStorageReq == null)
    {
        newItemStorageReq = new Ttccgs016424()
        {
            TItem = itemStorageReq.TItem,
            TSrq1 = itemStorageReq.TSrq1,
            TSrq2 = itemStorageReq.TSrq2,
            TSq27 = itemStorageReq.TSq27,
            TStmp = itemStorageReq.TStmp,
            TRcdVers = itemStorageReq.TRcdVers,
            TRefcntd = itemStorageReq.TRefcntd,
            TRefcntu = itemStorageReq.TRefcntu
        };

        try
        {
            _LN.Ttccgs016424s.Add(newItemStorageReq);
            _LN.SaveChanges();
        }
        catch (Exception ex)
        {
            return BadRequest(ex.Message);  
        }

        return StatusCode(StatusCodes.Status201Created);
    }
    else
    {
        return StatusCode(StatusCodes.Status412PreconditionFailed, "Item Storage Requirement already exists.");
    }
}

Here is my CORS configuration in my startup.cs for the API (note that my origin is part of the origins array):

services.AddCors(setup => {
    setup.DefaultPolicyName = "open";
    setup.AddDefaultPolicy(p => {
        p.AllowAnyHeader();
        p.WithMethods("OPTIONS", "GET", "POST", "PUT", "DELETE");
        p.WithOrigins(origins);
        p.AllowCredentials();
     });
});

Request headers sent:

OPTIONS /api/LN/InsertItemStorageRequirement HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate, br, zstd
Accept-Language: en-US,en;q=0.9
Access-Control-Request-Headers: content-type
Access-Control-Request-Method: POST
Connection: keep-alive
Host: localhost:31227
Origin: http://localhost:14612
Referer: http://localhost:14612/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
User-Agent: Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Mobile Safari/537.36 Edg/128.0.0.0

Response:

HTTP/1.1 401 Unauthorized
Cache-Control: private
Content-Type: text/html; charset=utf-8
Server: Microsoft-IIS/10.0
WWW-Authenticate: Negotiate
WWW-Authenticate: NTLM
X-Powered-By: ASP.NET
Date: Wed, 11 Sep 2024 23:43:25 GMT
Content-Length: 5995

I’ve tried changing the AJAX call to use credentials: 'include'.

And tried changed the

data: '{itemStorageReq: "' + JSON.stringify(tempLNStorage) + '"}'

Neither have resulted in a successful POST to the API.

GET requests to a different method in the same controller of the API are successful.

I suspect that this isn’t truly a CORS issue, but rather a data mismatch between what the Ajax is sending and what the API is expecting.

Any suggestions on how to troubleshoot this issue?

Update
IIS has the CORs module installed:

Update 2 9/23/24

Moved my app.UseCors() to between app.UseRouting() and app.UseEndpoints() before calling authenticate and authorize in the configure() of startup.cs.

app.UseRouting();

app.UseCors("open");

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

app.UseEndpoints(endpoints =>
{
        endpoints.MapControllers();
});

Also, I am using endpoint routing, which according to MS, means that the CORS Module won’t automatically respond to OPTIONS requests: https://learn.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-6.0#httpoptions-attribute-for-preflight-requests.

In the same link MS recommends writing code in your endpoint to authorize the OPTIONS. So something like this?

[HttpOptions("InsertItemStorageRequirement")]
public IActionResult PreFlightRoute() {
       return NoContent();
}

The error message you shared contains WWW-Authenticate: NTLM so that the preflight request which doesn’t contains windows auth credential shall be blocked and get 401 error.

A CORS preflight request is used to determine whether the resource
being requested is set to be shared across origins by the
server…..The OPTIONS requests are always anonymous, so CORS module
provides IIS servers a way to correctly respond to the preflight
request even if anonymous authentification needs to be disabled
server-wise

Since the preflight request can’t get the desired CORS policy back, the POST request gets CORS error is the expected behavior. Similar to this ticket.

If you are working locally, the workaround is allowing anonymous. In your API project launchsettings.json, you might need to set "anonymousAuthentication": true like below. And if you are hosting your app in IIS now, you can use CORS module just like the document I shared above said.

{
  "iisSettings": {
    "windowsAuthentication": true,
    "anonymousAuthentication": true,
}

6

I ended up modifying permissions on IIS according to this tutorial: https://techcommunity.microsoft.com/t5/iis-support-blog/putting-it-all-together-cors-tutorial/ba-p/775331.

Enabled anonymous for the API. Then added authorization rules to limit Anonymous requests to OPTIONS verbs only. Finally, I added another authorization rule to allow all users from the ‘USERS’ group.

The article above is dated, describing these changes as being superseded by the IIS CORS module, which has been implemented on my API since the beginning, but which failed to act on OPTIONS sent to the API. The CORS module, with a properly configured pipeline, should intercept OPTIONS requests without having to enable Anonymous Authentication for the entire API.

I did follow the MS advice for properly arranging middleware in a .NET Core app: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware/?view=aspnetcore-6.0#middleware-order-1, but it did not result in a successful POST request for me.

I also had attempted to implement these suggestions from MS for when you are using endpoint routing (which I am): https://learn.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-6.0#httpoptions-attribute-for-preflight-requests. They also did not allow OPTIONS requests to pass.

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật