angularangular-http-interceptors

Angular Http Interceptor - Modifying headers causes CORS


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)


Solution

  • 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:

    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).

    <?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>