← Back to Articles         
CORS in ASP.NET Core: Origin, Preflight & OPTIONS

CORS in ASP.NET Core: Origin, Preflight & OPTIONS

Published on 01 Oct 2026     8 min read Angular
CORS

CORS in ASP.NET Core: Origin, Preflight & OPTIONS

These four concepts are directly connected:

Origin
   ↓
Cross-origin request
   ↓
CORS
   ↓
Preflight may be required
   ↓
Browser sends OPTIONS
   ↓
Server says what is allowed
   ↓
Browser sends actual request

1. How Do You Configure CORS in ASP.NET Core?

What is CORS Configuration?

ASP.NET Core CORS configuration tells the browser which frontend origins are allowed to access the API.

For example:

Angular
http://localhost:4200

        ↓

ASP.NET Core Web API
https://localhost:7001

Because these are different origins, configure the API to allow the Angular origin.

Full Simple Code — Program.cs

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();


// 1. Register CORS
builder.Services.AddCors(options =>
{
    options.AddPolicy("AngularApp", policy =>
    {
        policy
            .WithOrigins("http://localhost:4200")
            .AllowAnyHeader()
            .AllowAnyMethod();
    });
});


var app = builder.Build();

app.UseHttpsRedirection();


// 2. Apply CORS
app.UseCors("AngularApp");


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

app.MapControllers();

app.Run();

There are two important steps.

Step 1 — Register CORS

builder.Services.AddCors(options =>
{
    options.AddPolicy("AngularApp", policy =>
    {
        policy
            .WithOrigins("http://localhost:4200")
            .AllowAnyHeader()
            .AllowAnyMethod();
    });
});

We created a policy named:

AngularApp

Step 2 — Apply CORS Middleware

app.UseCors("AngularApp");

Now ASP.NET Core applies that policy to requests.


Understanding the Configuration

WithOrigins()

.WithOrigins("http://localhost:4200")

Specifies which origin is allowed.

You can allow multiple trusted origins:

.WithOrigins(
    "http://localhost:4200",
    "https://www.jntech.in"
)

AllowAnyHeader()

.AllowAnyHeader()

Allows request headers permitted by the CORS policy, including headers your Angular application commonly uses, such as:

Authorization
Content-Type

For example:

Authorization: Bearer eyJhbGciOi...
Content-Type: application/json

AllowAnyMethod()

.AllowAnyMethod()

Allows HTTP methods such as:

GET
POST
PUT
PATCH
DELETE

You can also restrict the methods.

.WithMethods(
    "GET",
    "POST",
    "PUT",
    "DELETE"
)

Development vs Production

Development:

.WithOrigins(
    "http://localhost:4200"
)

Production:

.WithOrigins(
    "https://www.jntech.in"
)

Or both:

.WithOrigins(
    "http://localhost:4200",
    "https://www.jntech.in"
)

In a production application, the allowed origins are often placed in configuration rather than hard-coded.


2. What is an Origin?

Definition

An origin identifies the security context from which a browser page was loaded.

It consists of:

Scheme + Host + Port

For example:

https://www.example.com:443
  │           │          │
Scheme       Host       Port

Example

Angular:

http://localhost:4200

contains:

Scheme = http
Host   = localhost
Port   = 4200

ASP.NET Core:

https://localhost:7001

contains:

Scheme = https
Host   = localhost
Port   = 7001

They are different origins because the scheme and port differ.


Same-Origin Examples

These have the same origin:

https://www.jntech.in/articles
https://www.jntech.in/contact
https://www.jntech.in/admin/login

Why?

Scheme = https
Host   = www.jntech.in
Port   = same/default HTTPS port

The path does not determine the origin.


Different-Origin Examples

Different scheme

http://www.jntech.in

https://www.jntech.in

Different origin.

Different host

https://www.jntech.in

https://api.jntech.in

Different origin.

Even though both belong to the same parent domain, the hosts are different.

Different port

http://localhost:4200

http://localhost:5000

Different origin.


Easy Formula

Remember:

ORIGIN
  =
Scheme
  +
Host
  +
Port

If one of these differs:

Different Origin

3. What is a Preflight Request?

What is it?

A preflight request is a request automatically sent by the browser before certain cross-origin requests.

The browser is essentially asking the server:

"Before I send the real request, do you allow this origin, HTTP method, and these headers?"

The preflight request uses the HTTP:

OPTIONS

method.


Example

Suppose Angular wants to perform:

DELETE https://localhost:7001/api/products/10
Authorization: Bearer <JWT>

Before sending the DELETE, the browser may send:

OPTIONS /api/products/10
Origin: http://localhost:4200
Access-Control-Request-Method: DELETE
Access-Control-Request-Headers: authorization

This is the preflight request.


ASP.NET Core Response

If the CORS policy allows the request, the response can contain headers such as:

Access-Control-Allow-Origin: http://localhost:4200
Access-Control-Allow-Methods: DELETE
Access-Control-Allow-Headers: authorization

The browser sees:

Origin        → Allowed
DELETE        → Allowed
Authorization → Allowed

Then it sends the actual request:

DELETE /api/products/10
Authorization: Bearer <JWT>

Complete Preflight Flow

Angular wants:

DELETE /api/products/10
Authorization: Bearer JWT

             ↓

Browser detects cross-origin
request requiring preflight

             ↓

OPTIONS /api/products/10

             ↓

ASP.NET Core CORS Middleware

             ↓

Is Origin allowed?
Is DELETE allowed?
Is Authorization header allowed?

             ↓

          YES

             ↓

CORS response headers

             ↓

Browser sends actual:

DELETE /api/products/10

             ↓

ASP.NET Core API

Does Every CORS Request Have a Preflight?

No.

Some requests qualify as CORS simple requests and can be sent without a preflight.

For example, under the required restrictions, a simple:

GET /api/products

may not require a preflight.

But requests involving things such as:

PUT
DELETE
PATCH

Authorization header

certain Content-Type values

custom headers

commonly require a preflight.


JWT Example

Your Angular interceptor may add:

const authRequest = req.clone({
  setHeaders: {
    Authorization:
      `Bearer ${token}`
  }
});

The actual request becomes:

GET /api/products
Authorization: Bearer <JWT>

Because of the Authorization header, a cross-origin request will generally require a CORS preflight.

Angular
   ↓
OPTIONS
   ↓
CORS check
   ↓
Allowed
   ↓
GET
Authorization: Bearer JWT
   ↓
ASP.NET Core

4. What is an HTTP OPTIONS Request?

What is OPTIONS?

OPTIONS is a standard HTTP method.

It is used to ask a server about communication options available for a resource.

Common HTTP methods include:

GET      → Retrieve

POST     → Create

PUT      → Update/replace

PATCH    → Partial update

DELETE   → Delete

OPTIONS  → Ask what communication is allowed

In CORS, browsers use OPTIONS for preflight requests.


Example OPTIONS Request

Browser sends:

OPTIONS /api/products/10 HTTP/1.1

Origin: http://localhost:4200

Access-Control-Request-Method: DELETE

Access-Control-Request-Headers: authorization

Notice something important.

The browser is not deleting the product yet.

It is asking:

Can http://localhost:4200

send a DELETE request

using the Authorization header

to this API?

Server Response

ASP.NET Core CORS middleware might respond:

HTTP/1.1 204 No Content

Access-Control-Allow-Origin:
http://localhost:4200

Access-Control-Allow-Methods:
DELETE

Access-Control-Allow-Headers:
authorization

Then the browser knows:

✓ Origin allowed
✓ DELETE allowed
✓ Authorization allowed

So it proceeds with:

DELETE /api/products/10
Authorization: Bearer <JWT>

Preflight vs OPTIONS

These terms are related but aren't identical.

Term Meaning
OPTIONS An HTTP method
Preflight A CORS browser check performed using OPTIONS

So:

Preflight Request
       ↓
uses
       ↓
HTTP OPTIONS

An OPTIONS request can exist for purposes other than CORS, but CORS preflight specifically uses OPTIONS.


Do We Need to Create an OPTIONS Controller Action?

Normally, no.

You generally don't need:

[HttpOptions]
public IActionResult Options()
{
    ...
}

just to support normal CORS preflight.

ASP.NET Core's CORS middleware handles the preflight when CORS is correctly configured:

builder.Services.AddCors(...);

and:

app.UseCors("AngularApp");

How All Four Concepts Connect

Suppose:

Angular
http://localhost:4200

ASP.NET Core
https://localhost:7001

Step 1 — Browser compares origins

http://localhost:4200

vs

https://localhost:7001

They differ.

Therefore:

Cross-Origin Request

Step 2 — Angular wants to send

DELETE /api/products/10
Authorization: Bearer <JWT>

Step 3 — Browser determines preflight is needed

It first sends:

OPTIONS /api/products/10

Step 4 — ASP.NET Core CORS middleware checks

Origin allowed?

Method allowed?

Header allowed?

Your configuration:

policy
    .WithOrigins(
        "http://localhost:4200"
    )
    .AllowAnyHeader()
    .AllowAnyMethod();

allows them.

Step 5 — Browser sends actual request

DELETE /api/products/10
Authorization: Bearer <JWT>

Step 6 — Authentication and authorization happen

JWT validation
      ↓
Authentication
      ↓
Authorization
      ↓
[Authorize(Roles = "Admin")]
      ↓
Controller

CORS vs Preflight vs OPTIONS

A simple way to remember:

CORS
│
├── Rule governing browser
│   cross-origin access
│
├── Origin
│      ↓
│   Who is making the
│   browser request?
│
├── Preflight
│      ↓
│   Browser asks permission
│   before certain requests
│
└── OPTIONS
       ↓
    HTTP method used
    for the preflight

Key Points

  • Configure CORS in ASP.NET Core using AddCors().
  • Apply the policy using UseCors().
  • WithOrigins() specifies trusted frontend origins.
  • AllowAnyHeader() permits request headers according to that policy.
  • AllowAnyMethod() permits HTTP methods.
  • An origin consists of scheme + host + port.
  • Different port means a different origin.
  • Different scheme means a different origin.
  • Different host means a different origin.
  • A preflight is a browser check before certain cross-origin requests.
  • Preflight uses HTTP OPTIONS.
  • The browser sends preflight automatically.
  • You normally don't manually send the OPTIONS request from Angular.
  • You normally don't need to create an OPTIONS controller action for CORS.
  • JWT requests using an Authorization header commonly cause preflight.
  • CORS is separate from authentication and authorization.

Interview Questions & Answers

1. How do you configure CORS in ASP.NET Core?

Register a CORS policy:

builder.Services.AddCors(options =>
{
    options.AddPolicy(
        "AngularApp",
        policy =>
        {
            policy
                .WithOrigins(
                    "http://localhost:4200")
                .AllowAnyHeader()
                .AllowAnyMethod();
        });
});

Then apply it:

app.UseCors("AngularApp");

2. What is an origin?

An origin consists of:

Scheme + Host + Port

For example:

https://localhost:7001

If the scheme, host, or port differs, the browser treats it as a different origin.


3. What is a preflight request?

A preflight request is an automatic browser request sent before certain cross-origin requests to check whether the server permits the requested origin, method, and headers.

It uses:

OPTIONS

4. What is an HTTP OPTIONS request?

OPTIONS is an HTTP method used to query communication options for a resource. In CORS, browsers use it to perform preflight checks.


5. Does Angular manually send the preflight request?

No. The browser automatically determines when a CORS preflight is necessary and sends the OPTIONS request.


6. Does every CORS request cause an OPTIONS request?

No. Some requests qualify as simple CORS requests and don't require preflight. Requests using methods or headers outside the safelisted set generally do.


7. Why does an Angular JWT request often trigger preflight?

Because Angular commonly sends:

Authorization: Bearer <JWT>

The Authorization header is not CORS-safelisted, so a cross-origin request using it generally requires preflight.


Interview Quick Answer

In ASP.NET Core, CORS is configured using AddCors() and applied with UseCors(). An origin is defined by scheme, host, and port. For certain cross-origin requests, the browser automatically sends a preflight request using the HTTP OPTIONS method to check whether the server permits the requested origin, HTTP method, and headers before sending the actual request.

← Back to Articles