CORS in Production and CORS with Cookies/Credentials
These two topics are closely related. The key production rule is:
Allow only the frontend origins that actually need browser access to your API, and use
AllowCredentials()only when cross-origin cookies/credentials are genuinely required.
1. How Should CORS Be Configured in Production?
Recommended Approach
Suppose your production architecture is:
Angular
https://www.jntech.in
↓
ASP.NET Core API
https://api.jntech.in
These are different origins because the hosts differ:
www.jntech.in
≠
api.jntech.in
Therefore CORS applies.
Configure the API to explicitly allow:
https://www.jntech.in
rather than allowing every origin.
Full Production Example
appsettings.json
{
"AllowedOrigins": [
"https://www.jntech.in"
]
}
Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
var allowedOrigins =
builder.Configuration
.GetSection("AllowedOrigins")
.Get<string[]>()!;
builder.Services.AddCors(options =>
{
options.AddPolicy(
"ProductionCors",
policy =>
{
policy
.WithOrigins(allowedOrigins)
.AllowAnyHeader()
.AllowAnyMethod();
});
});
var app = builder.Build();
app.UseHttpsRedirection();
app.UseCors("ProductionCors");
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
This means:
https://www.jntech.in
↓
Allowed
https://unknown-site.com
↓
Not allowed
Development vs Production
You may have different frontend origins in different environments.
Development
Angular:
http://localhost:4200
API:
https://localhost:7001
Production
Angular:
https://www.jntech.in
API:
https://api.jntech.in
You can configure them separately.
appsettings.Development.json
{
"AllowedOrigins": [
"http://localhost:4200"
]
}
appsettings.Production.json
{
"AllowedOrigins": [
"https://www.jntech.in"
]
}
Then the same Program.cs reads:
var allowedOrigins =
builder.Configuration
.GetSection("AllowedOrigins")
.Get<string[]>()!;
This is cleaner than hard-coding environment-specific URLs.
Multiple Production Frontends
Suppose you have:
Public Angular:
https://www.jntech.in
Admin Angular:
https://admin.jntech.in
Configure:
{
"AllowedOrigins": [
"https://www.jntech.in",
"https://admin.jntech.in"
]
}
ASP.NET Core:
policy
.WithOrigins(allowedOrigins)
.AllowAnyHeader()
.AllowAnyMethod();
Should Production Use AllowAnyOrigin()?
For an API intended only for your known frontend applications, generally prefer:
.WithOrigins(
"https://www.jntech.in"
)
rather than:
.AllowAnyOrigin()
because AllowAnyOrigin() permits browser access from any origin.
Use the least-privilege principle:
Allow only what is required.
Can Angular and API Avoid CORS Entirely?
Yes, depending on deployment architecture.
Suppose both are served through:
https://www.jntech.in
For example:
https://www.jntech.in/
↓
Angular
https://www.jntech.in/api/products
↓
ASP.NET Core
From the browser's perspective:
Scheme = https
Host = www.jntech.in
Port = 443
for both.
Therefore:
Same Origin
↓
No cross-origin CORS requirement
A reverse proxy/API gateway can be used to expose both under the same public origin.
Production CORS Checklist
For production:
- Use HTTPS.
- Prefer explicit
WithOrigins(...). - Keep origins in environment-specific configuration.
- Allow only required methods and headers where practical.
- Don't use CORS as authentication.
- Continue protecting endpoints with
[Authorize]. - Add
AllowCredentials()only when browser credentials/cookies must cross origins. - Don't combine wildcard origin with credentialed CORS.
2. How Does CORS Work When Credentials/Cookies Are Used?
This becomes especially important with the refresh-token design we discussed.
Suppose:
Angular
https://www.jntech.in
↓
ASP.NET Core
https://api.jntech.in
ASP.NET Core stores the refresh credential in an:
HttpOnly
Secure
Cookie
Now Angular needs the browser to include cookies in appropriate cross-origin requests.
Full ASP.NET Core Configuration
Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddCors(options =>
{
options.AddPolicy(
"AngularApp",
policy =>
{
policy
.WithOrigins(
"https://www.jntech.in"
)
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();
});
});
var app = builder.Build();
app.UseHttpsRedirection();
app.UseCors("AngularApp");
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
The important addition is:
.AllowCredentials()
This tells the CORS middleware that credentialed cross-origin requests from the explicitly allowed origin are permitted.
Angular Configuration
Angular must also request credential handling when needed:
this.http.post(
'https://api.jntech.in/api/auth/refresh',
{},
{
withCredentials: true
}
);
The important part is:
withCredentials: true
Both Sides Must Agree
For cross-origin cookie usage:
Angular
withCredentials: true
+
ASP.NET Core
AllowCredentials()
+
Explicit trusted origin
WithOrigins(...)
↓
Credentialed CORS request
Example Login Flow
Angular sends:
login(
username: string,
password: string
) {
return this.http.post(
'https://api.jntech.in/api/auth/login',
{
username,
password
},
{
withCredentials: true
}
);
}
ASP.NET Core authenticates the user and creates a refresh-token cookie.
Response.Cookies.Append(
"refreshToken",
refreshToken,
new CookieOptions
{
HttpOnly = true,
Secure = true,
SameSite =
SameSiteMode.Strict,
Expires =
DateTimeOffset.UtcNow
.AddDays(7)
});
The cookie is:
HttpOnly
↓
Angular JavaScript cannot read it directly
Secure
↓
Sent only over HTTPS
Cookie SameSite behavior depends on whether the browser considers the frontend/API relationship same-site or cross-site, so choose Strict, Lax, or None based on the actual deployment topology rather than applying one setting universally.
Refresh Flow
Later the access token expires:
API Request
↓
401 Unauthorized
Angular calls:
this.http.post(
'https://api.jntech.in/api/auth/refresh',
{},
{
withCredentials: true
}
);
Angular doesn't need to read the refresh token.
Instead:
Angular
↓
POST /refresh
withCredentials: true
↓
Browser
↓
Automatically attaches eligible cookie
↓
ASP.NET Core
↓
Reads refresh token
↓
Validates it
↓
Issues new access token
This is one advantage of an HttpOnly refresh cookie.
Why Can't Angular Read an HttpOnly Cookie?
Because:
HttpOnly = true
instructs the browser not to expose the cookie value to normal JavaScript APIs.
Therefore Angular cannot simply do:
const refreshToken =
document.cookie;
and retrieve an HttpOnly refresh-token value.
That's intentional.
Angular JavaScript
X
│
│ cannot directly read
▼
HttpOnly Refresh Cookie
Browser
│
│ automatically sends
▼
ASP.NET Core
Why Can't We Use AllowAnyOrigin() + AllowCredentials()?
This configuration is invalid/insecure:
policy
.AllowAnyOrigin()
.AllowCredentials();
Why?
Because you're effectively saying:
Any website
+
Credentialed requests
Credentialed CORS requires a specific allowed origin rather than wildcard *.
Use:
policy
.WithOrigins(
"https://www.jntech.in"
)
.AllowCredentials();
Response Headers
For a credentialed CORS request, the API can respond with headers such as:
Access-Control-Allow-Origin: https://www.jntech.in
Access-Control-Allow-Credentials: true
Notice:
Access-Control-Allow-Origin: *
is not used for this credentialed request.
Instead:
Access-Control-Allow-Origin: https://www.jntech.in
explicitly identifies the permitted origin.
Preflight with Credentials
Suppose Angular sends a request requiring preflight.
The browser may first send:
OPTIONS /api/auth/refresh
Origin: https://www.jntech.in
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type
ASP.NET Core evaluates:
Origin allowed?
↓
POST allowed?
↓
Headers allowed?
↓
Credentials allowed?
If the policy allows it, the browser proceeds with the actual request.
CORS Credentials vs JWT Bearer Token
There is an important distinction.
Bearer Token
Angular explicitly adds:
Authorization: Bearer <JWT>
using an interceptor.
Angular JavaScript
↓
reads access token
↓
adds Authorization header
HttpOnly Cookie
Angular cannot read the cookie.
Angular
↓
withCredentials
↓
Browser
↓
automatically attaches eligible cookie
So a common hybrid design is:
Access Token
↓
Angular memory
↓
Authorization: Bearer
Refresh Token
↓
HttpOnly Secure Cookie
↓
Browser manages it
Important: CORS and Cookies Are Not Enough
Using:
.AllowCredentials()
doesn't mean your cookie setup is automatically secure.
You still need to consider:
HTTPS
Secure = true
HttpOnly
HttpOnly = true
SameSite
Choose an appropriate setting:
SameSite = ...
CSRF
Because browsers automatically attach cookies, cookie-authenticated operations may require CSRF protection depending on the architecture.
Authentication/Authorization
Sensitive API endpoints still need:
[Authorize]
or:
[Authorize(Roles = "Admin")]
Complete Production Architecture
Angular
https://www.jntech.in
│
│
├──── Access Token
│ Authorization: Bearer
│
│
└──── withCredentials
│
▼
Browser
│
│ HttpOnly Refresh Cookie
▼
ASP.NET Core
https://api.jntech.in
│
▼
CORS
│
├── Origin allowed?
├── Method allowed?
├── Header allowed?
└── Credentials allowed?
│
▼
Authentication
│
▼
Authorization
│
▼
Controller
AllowAnyOrigin() vs AllowCredentials()
| Configuration | Meaning |
|---|---|
AllowAnyOrigin() |
Any origin |
WithOrigins(...) |
Specific origins |
AllowCredentials() |
Allow credentialed CORS requests |
AllowAnyOrigin() + AllowCredentials() |
Invalid combination |
WithOrigins(...) + AllowCredentials() |
Appropriate pattern when cross-origin credentials are needed |
Key Points
- In production, explicitly allow trusted frontend origins.
- Prefer
WithOrigins()overAllowAnyOrigin()for APIs intended for known applications. - Store production origins in configuration.
- Use HTTPS.
- CORS may not be necessary when Angular and the API are exposed through the exact same origin.
- For cross-origin cookie usage, configure
AllowCredentials(). - Angular may need
withCredentials: true. - Credentialed CORS requires explicit origins.
- Don't combine
AllowAnyOrigin()withAllowCredentials(). HttpOnlyprevents JavaScript from directly reading the cookie.Securelimits cookie transmission to HTTPS.SameSitecontrols important cross-site cookie behavior.- Cookie-based authentication/refresh flows require CSRF consideration.
- CORS never replaces ASP.NET Core authentication or authorization.
Interview Questions & Answers
1. How should CORS be configured in production?
Allow only known frontend origins:
policy
.WithOrigins(
"https://www.jntech.in"
)
.AllowAnyHeader()
.AllowAnyMethod();
Avoid unnecessarily using AllowAnyOrigin() for a private application API.
2. What does AllowCredentials() do?
It permits credentialed cross-origin requests, such as requests involving eligible cookies.
.AllowCredentials()
3. How does Angular send cookies in a cross-origin request?
When required, use:
{
withCredentials: true
}
The browser then handles eligible cookies according to the cookie and CORS rules.
4. Can Angular read an HttpOnly cookie?
No.
That is the purpose of:
HttpOnly = true
The browser manages the cookie and can attach it to eligible requests.
5. Can AllowAnyOrigin() be combined with AllowCredentials()?
No.
Use an explicit origin:
.WithOrigins(
"https://www.jntech.in"
)
.AllowCredentials();
6. What CORS headers are important for credentialed requests?
Typically:
Access-Control-Allow-Origin: https://www.jntech.in
Access-Control-Allow-Credentials: true
The origin must be explicit rather than *.
7. Is withCredentials: true alone enough?
No.
The server must also permit the origin and credentials:
.WithOrigins(...)
.AllowCredentials()
and the cookie itself must be eligible to be sent according to Secure, SameSite, domain/path, and browser rules.
8. Do we always need CORS in production?
No. If Angular and the API are exposed through the same scheme, host, and port, the browser sees them as the same origin and cross-origin CORS is not required.
Interview Quick Answer
In production, ASP.NET Core should normally allow only explicitly trusted Angular origins using
WithOrigins(). When cross-origin cookies are required, the server usesAllowCredentials()and Angular useswithCredentials: true. Credentialed CORS cannot use the wildcardAllowAnyOrigin(); the permitted origin must be explicitly specified.