CORS Policy Blocking POST Request in ASP.NET Core Minimal API with IIS Express (GET Works)

Anonymous
2025-07-03T14:45:46.5766667+00:00

I'm developing an ASP.NET Core Minimal API using Visual Studio 2022 and running it with IIS Express. While GET requests work as expected, POST requests are being blocked due to CORS policy.

Access to XMLHttpRequest at 'https://localhost:44302/api/xxx' from origin '<origin>' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

What I've tried:

  • Configured CORS in Program.cs using AddCors and UseCors.
  • Allowed any header and method, and specified the frontend origin.
  • Added middleware to handle OPTIONS requests.
  • Confirmed that the issue only occurs with POST requests (not GET).

Environment:

  • ASP.NET Core Minimal API
  • .NET SDK: Version: 9.0.301
  • Visual Studio 2022
  • IIS Express
  • Windows Authentication (Negotiate) enabled

How can I properly configure CORS to allow POST requests in this setup, especially when using Windows Authentication and IIS Express?

Developer technologies | ASP.NET | ASP.NET API
0 comments No comments
{count} votes

Answer accepted by question author
  1. Jack Dang (WICLOUD CORPORATION) 5,960 Reputation points Microsoft External Staff Moderator
    2025-07-04T09:14:50.3066667+00:00

    Hello @Manoj,

    This issue is commonly caused by the way CORS handles preflight OPTIONS requests, which are automatically sent by the browser before a POST request. If your server doesn't respond correctly to these preflight requests, the browser will block the actual POST.

    Here are some steps to help resolve the issue:

    • CORS Policy Configuration: Ensure your backend is configured to allow requests from your frontend origin. This includes allowing specific HTTP methods (like POST), headers, and credentials. The CORS policy should be applied early in the middleware pipeline.
    • OPTIONS Request Handling: POST requests trigger a preflight OPTIONS request. Your API must be able to respond to OPTIONS requests appropriately. If the server doesn't handle these, the browser will block the request.
    • Middleware Order: The order in which middleware is applied matters. CORS should be configured and applied before authentication and authorization middleware to ensure it can handle requests properly.
    • Windows Authentication Considerations: When using Windows Authentication, cross-origin requests must include credentials. Your CORS policy must explicitly allow credentials, and your frontend must be configured to send them.
    • Testing Outside IIS Express: IIS Express can sometimes behave differently than Kestrel (the default ASP.NET Core web server). Try running your API with Kestrel to see if the issue persists. This can help isolate whether IIS Express is contributing to the problem.

    Hope my answer would help.

    1 person found this answer helpful.

4 additional answers

Sort by: Most helpful
  1. Deleted

    This answer has been deleted due to a violation of our Code of Conduct. The answer was manually reported or identified through automated detection before action was taken. Please refer to our Code of Conduct for more information.


    Comments have been turned off. Learn more

  2. Deleted

    This answer has been deleted due to a violation of our Code of Conduct. The answer was manually reported or identified through automated detection before action was taken. Please refer to our Code of Conduct for more information.


    Comments have been turned off. Learn more

  3. SurferOnWww 4,951 Reputation points
    2025-07-04T01:11:35.9033333+00:00

    Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

    It seems that the preflight request has not been properly processed. Please check if the request and response include the headers required for CORS. Shown below are sample when the preflight request has been successfully processed.

    Preflight request

    enter image description here

    Because in this sample the request header includes Content-Type: application/json, browser has sent the prefight request with the HTTP method of OPTIONS and the request headers of Access-Control-Allow-Headers and Access-Control-Allow-Methods and Origin.

    The Web server returned the response headers including Access-Control-Allow-Headers, Access-Control-Allow-Methods and Access-Control-Allow-Origin as expected in CORS operation.

    POST after preflight request

    enter image description here Since the response of preflight request is successful, the browser has POSTed data and obtained the response from the Web server properly.

    0 comments No comments

  4. SurferOnWww 4,951 Reputation points
    2025-07-04T05:25:23.0133333+00:00

    Additional Info

    I have confirmed that the CORS works fine for both GET and POST in the Minimal API only by adding AddCors and UseCors to Program.cs. Details are described below. Please try.

    My environment:

    • The Minimal API app created according to the Microsoft tutorial Tutorial: Create a minimal API with ASP.NET Core
    • Visual Studio 2022 Version 17.14.7
    • Target Framework .NET 9.0
    • IIS Express
    • No authentication - different from yours, but I don't think this has affect on CORS.

    AddCors and UseCors are added to the Program.cs, as follows. Note that AllowAnyHeader() and AllowAnyMethod() are required for the preflight request.

    using Microsoft.EntityFrameworkCore;
    
    namespace MinimalAPI
    {
        public class Program
        {
            // Code added for CORS
            const string MyAllowAnyOrigins = "_myAllowAnyOrigins";
    
            public static void Main(string[] args)
            {
                var builder = WebApplication.CreateBuilder(args);
    
                // Code added for CORS
                builder.Services.AddCors(options =>
                {
                    options.AddPolicy(name: MyAllowAnyOrigins,
                                      policy =>
                                      {
                                          policy.AllowAnyOrigin()
                                                .AllowAnyHeader()
                                                .AllowAnyMethod();
                                      });
                });
    
                builder.Services.AddDbContext<TodoDb>(opt => opt.UseInMemoryDatabase("TodoList"));
                builder.Services.AddDatabaseDeveloperPageExceptionFilter();
                var app = builder.Build();
    
                // Code added for CORS
                app.UseCors(MyAllowAnyOrigins);
    
                app.MapGet("/todoitems", async (TodoDb db) =>
                    await db.Todos.ToListAsync());
    
                app.MapGet("/todoitems/complete", async (TodoDb db) =>
                    await db.Todos.Where(t => t.IsComplete).ToListAsync());
    
                app.MapGet("/todoitems/{id}", async (int id, TodoDb db) =>
                    await db.Todos.FindAsync(id)
                        is Todo todo
                            ? Results.Ok(todo)
                            : Results.NotFound());
    
                app.MapPost("/todoitems", async (Todo todo, TodoDb db) =>
                {
                    db.Todos.Add(todo);
                    await db.SaveChangesAsync();
    
                    return Results.Created($"/todoitems/{todo.Id}", todo);
                });
    
                app.MapPut("/todoitems/{id}", async (int id, Todo inputTodo, TodoDb db) =>
                {
                    var todo = await db.Todos.FindAsync(id);
    
                    if (todo is null) return Results.NotFound();
    
                    todo.Name = inputTodo.Name;
                    todo.IsComplete = inputTodo.IsComplete;
    
                    await db.SaveChangesAsync();
    
                    return Results.NoContent();
                });
    
                app.MapDelete("/todoitems/{id}", async (int id, TodoDb db) =>
                {
                    if (await db.Todos.FindAsync(id) is Todo todo)
                    {
                        db.Todos.Remove(todo);
                        await db.SaveChangesAsync();
                        return Results.NoContent();
                    }
    
                    return Results.NotFound();
                });
    
                app.Run();
            }
        }
    }
    

    I have used the following JavaScript in the cross origin Web app to request the app.MapPost of above Minimal API app:

    const url = "https://localhost:44374/todoitems";
    
    const minimalApiPost = async () => {
        const params = {
            method: "POST",
            body: '{"name":"walking dog","isComplete":true}',
            headers: { 'Content-Type': 'application/json' }
        }
        const response = await fetch(url, params);
        if (response.ok) {
            const data = await response.json();
            elem.innerHTML = "";
            elem.insertAdjacentHTML("beforeend",
                `<li>${data.id}: ${data.name}, ${data.isComplete}</li>`);
        } else {
            elem.innerHTML = "Fail";
        }
    };
    

    Result was successful:

    Preflight enter image description here

    Post after preflight

    enter image description here

    0 comments No comments

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.