1

I have defined an http interceptor. Inside the interceptor I have the following code:

let newReq = req.clone({
  withCredentials: true,
  responseType: 'json'
});

Now I need to modify all requests and add an extra header Demo with the value of foo

I tried the following

let newReq = req.clone({
  withCredentials: true,
  responseType: 'json',
  setHeaders: {'Demo' : 'foo'}
});

However I notice in the network tab that this removes almost all headers including Host & Origin from my request and it leads to CORS issues with the API that I am communicating with

Is there any way to fix this issue ? (I want to have all previous headers in my cloned request and just add a new one)

Manos Kounelakis
  • 2,848
  • 5
  • 31
  • 55

2 Answers2

1

Your code seems to be working fine and and it does send the previous and new headers successfully. The culprit is the option withCredentials: true which causes the following error:

Access to XMLHttpRequest at 'https://example.com' from origin 'http://localhost:4200' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.

As the error suggests, the server is probably sending header Access-Control-Allow-Origin: * in pre-flight check (response of OPTIONS request). Your request will only work if server sends the header Access-Control-Allow-Origin: http://localhost:4200 (or whatever your origin is).

The reason why you cannot Access-Control-Allow-Origin: * in combination with withCredentials: true is explained here: CORS: Cannot use wildcard in Access-Control-Allow-Origin when credentials flag is true

I created a backend to reproduce this issue. Doing following steps will solve your problem:

  • Add http://localhost:4200 (or your origin) to the allow CORS origin list (you cannot set it as *).
  • Allow custom headers to be passed to your backend by setting access-control-allow-headers to *.
  • Set allow_credentials in your CORS settings to true.

If you are using Python (Fast API), you can do above settings like this (tested and works):

app = FastAPI()

origins = [
    "http://localhost:4200"
]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

If you are using .NET Core, you can do above settings like this (not tested):

var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";

var builder = WebApplication.CreateBuilder(args);

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

builder.Services.AddControllers();

var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();

app.UseCors(MyAllowSpecificOrigins);

app.UseAuthorization();

app.MapControllers();

app.Run();

Also do similar settings on IIS (if you are using IIS).

  • allowCredentials="true"
  • allowAllRequestedHeaders="true"
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <cors enabled="true" failUnlistedOrigins="true">
            <add origin="http://localhost:4200"
                 allowCredentials="true"
                 maxAge="120"> 
                <allowHeaders allowAllRequestedHeaders="true">
                    <add header="Demo" />
                </allowHeaders>
                <allowMethods>
                     <add method="DELETE" />
                     <add method="GET" />
                     <add method="POST" />
                     <add method="PUT" />
                     <add method="OPTIONS" />
                </allowMethods>
            </add>
        </cors>
    </system.webServer>
</configuration>
Syed Rafay
  • 1,405
  • 2
  • 15
  • 19
  • I am looking at the backend cors (dotnetcore) and I see that they have added the http://localhost:4200 origin. That is what bothers me – Manos Kounelakis May 30 '23 at 13:33
  • Does backend also allow your demo header? `access-control-allow-headers: demo` – Syed Rafay May 30 '23 at 13:36
  • Yes I see it has allow any header – Manos Kounelakis May 30 '23 at 13:39
  • I will test it later with a proper backend, right now I was testing it with https://webhook.site/ and unfortunately it doesn't allow headers to be set and sent back to the client. – Syed Rafay May 30 '23 at 13:46
  • @ManosKounelakis your backend has an issue, I was able to reproduce and solve the issue. Check updated answer – Syed Rafay May 31 '23 at 11:23
  • Thanks for your answer. My project has 2 configuration. 1 is IIS server and the other is dev . I found out that it happends only when I run the IIS configuration. So it must have to do something with this – Manos Kounelakis May 31 '23 at 11:32
  • No worries, IIS also has similar settings. Added some of the IIS settings in answer as well. – Syed Rafay May 31 '23 at 11:42
0

Since you're adding a new header and that's causing the problem, my guess is that this is because the server is not including Demo in the Access-Control-Allow-Headers part of the OPTIONS response:

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers

I think you probably need to fix this on the backend.

Willow
  • 1,132
  • 5
  • 20
  • Hi . My issue is that all the previous headers (Host , Origin , etc are removed from my cloned request) not from the response. Sorry I have update my answer – Manos Kounelakis May 30 '23 at 12:58