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
OPTIONSrequest from Angular. - You normally don't need to create an
OPTIONScontroller action for CORS. - JWT requests using an
Authorizationheader 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 withUseCors(). An origin is defined by scheme, host, and port. For certain cross-origin requests, the browser automatically sends a preflight request using the HTTPOPTIONSmethod to check whether the server permits the requested origin, HTTP method, and headers before sending the actual request.