162

Yes, I know what you are thinking - yet another CORS question, but this time I'm stumped.

So to start off, the actual error message:

XMLHttpRequest cannot load http://localhost/Foo.API/token. 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'. Origin 'http://localhost:5000' is therefore not allowed access. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.

I'm not sure what is meant by credentials mode is 'include'?

So when I perform the request in postman, I experience no such error:

enter image description here

But when I access the same request through my angularjs web app, I am stumped by this error. Here is my angualrjs request/response. As you'll see the response is OK 200, but I still receive the CORS error:

Fiddler Request and Response:

The following image demonstrates the request and response from web front-end to API

Fiddler

So based on all the other posts I've read online, it seems like I'm doing the right thing, that's why I cannot understand the error. Lastly, here is the code I use within angualrjs (login factory):

enter image description here

CORS Implementation in API - Reference purposes:

Method 1 used:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        EnableCrossSiteRequests(config);
    }

    private static void EnableCrossSiteRequests(HttpConfiguration config)
    {
        var cors = new EnableCorsAttribute("*", "*", "*")
        {
            SupportsCredentials = true
        };
        config.EnableCors(cors);
    }
}

Method 2 used:

public void Configuration(IAppBuilder app)
{
    HttpConfiguration config = new HttpConfiguration();
 
    ConfigureOAuth(app);
 
    WebApiConfig.Register(config);
    app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
    app.UseWebApi(config);

}
Art
  • 2,836
  • 4
  • 17
  • 34
Richard Bailey
  • 2,658
  • 4
  • 27
  • 45
  • nice pictures, what are they of? To answer your question, if you include authentication, the access-control-allow-origin response **must** be the originating (browser page) host, it **can not** be `*` - so, the server side is doing CORS wrong - oh, and postman works because it's not a cross origin request – Jaromanda X Mar 15 '17 at 07:29
  • @JaromandaX, thanks for the response. The pictures demonstrate request/response as well as demonstrate the headers being passed. You asking the question, obviously states that it didn't perform it's goal... – Richard Bailey Mar 15 '17 at 07:34
  • My comment should be all you need to know - didn't need to see the pictures – Jaromanda X Mar 15 '17 at 07:37
  • So recently I decided to move away from cookies on my web api and rather make use of tokens. When I used cookies, my CORS work without any issues. So I'm struggling to understand how CORS is not implemented correctly on the server side – Richard Bailey Mar 15 '17 at 07:41
  • 1
    *if you include authentication, the `access-control-allow-origin` response must be the originating (browser page) host, it can not be `*`* – Jaromanda X Mar 15 '17 at 07:52
  • @JaromandaX ok, so if I understand correct, the request header has an `Origin` of http://localhost:5000, thus the response header `Access-Control-Allow-Origin`, should have a value of http://localhost:5000 – Richard Bailey Mar 15 '17 at 08:07
  • Yes. Localhost may be am issue though. Check documentation – Jaromanda X Mar 15 '17 at 08:11
  • lol - and what's around the next corner: `The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true' when the request's credentials mode is 'include'` – Richard Bailey Mar 15 '17 at 08:13
  • Do you actually need `widthCredentials: true`? You don't send an `Authorization` header and I presume you don't want to send cookies either. – a better oliver Mar 15 '17 at 09:01
  • @zeroflagL - I guess not. I'm basically trying various methods described op different threads to get a solution. Correct, I'm trying to move away from cookies – Richard Bailey Mar 15 '17 at 09:13
  • This is really unfortunate considering that the 'Origin: ' header is lost on 302 redirect in just about every major browser right now. Blindly echoing the origin to the response header is not the right move in all cases. – Umopepisdn Jul 07 '17 at 22:04

6 Answers6

168

The issue stems from your Angular code:

When withCredentials is set to true, it is trying to send credentials or cookies along with the request. As that means another origin is potentially trying to do authenticated requests, the wildcard ("*") is not permitted as the "Access-Control-Allow-Origin" header.

You would have to explicitly respond with the origin that made the request in the "Access-Control-Allow-Origin" header to make this work.

I would recommend to explicitly whitelist the origins that you want to allow to make authenticated requests, because simply responding with the origin from the request means that any given website can make authenticated calls to your backend if the user happens to have a valid session.

I explain this stuff in this article I wrote a while back.

So you can either set withCredentials to false or implement an origin whitelist and respond to CORS requests with a valid origin whenever credentials are involved

max23_
  • 6,531
  • 4
  • 22
  • 36
geekonaut
  • 5,714
  • 2
  • 28
  • 30
  • 6
    I am working on Angular 5 application with TypeScript. I need to give withCredentials as true else I will get Authorization Failed exception. How to solve this withCredentials:true – Ziggler May 07 '18 at 22:18
  • @Ziggler I had the same situation. Are you find solutions? – Pavel May 08 '18 at 23:00
  • @Ziggler I fined solution see my answer. – Pavel May 10 '18 at 20:41
  • 2
    I am still getting this error when using WithCredentials=TRUE and Access-Control-Allow-Origin=['http://localhost:4200'], and I am NOT using star * so the error message makes no sense anymore. ERROR MESSAGE: "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'. Origin 'http://localhost:4200' is therefore not allowed access. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute." – mruanova Jul 09 '18 at 20:36
  • @mruanova are you sure the Access-Control-Allow-Origin header is correctly set in the request? It sounds like something gets sent with a wildcard somewhere – geekonaut Jul 10 '18 at 05:11
  • fixed it by removing Access-Control-Allow-Origin entirely from the request, thanks – mruanova Jul 10 '18 at 11:15
  • On my side the request triggering the error is sent by the hot reload feature of webpack. Do you know where to change `withCredentials` to false? thanks – Alexis.Rolland May 26 '19 at 10:39
  • when i use WithCredentials=true, then I'm facing error in angular 5. Error Message: "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'. Origin 'localhost:4200' is therefore not allowed access. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute." – therightdoctors Jun 11 '19 at 16:53
42

If you are using CORS middleware and you want to send withCredentials boolean true, you can configure CORS like this:

var cors = require('cors');    
app.use(cors({credentials: true, origin: 'http://localhost:5000'}));
Ankur Kedia
  • 3,453
  • 1
  • 13
  • 15
  • Exactly the solution I needed. Thanks! – jacktim Dec 09 '22 at 08:56
  • Thanks! This is the answer I needed. In Spring Boot, this annotation provided the fix: @CrossOrigin( origins = { "http://localhost:4200", "https://www.blahblah.com" }, allowCredentials = "true" ) – Bruce Wilcox Jan 02 '23 at 21:38
12

Customizing CORS for Angular 5 and Spring Security (Cookie base solution)

On the Angular side required adding option flag withCredentials: true for Cookie transport:

constructor(public http: HttpClient) {
}

public get(url: string = ''): Observable<any> {
    return this.http.get(url, { withCredentials: true });
}

On Java server-side required adding CorsConfigurationSource for configuration CORS policy:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        // This Origin header you can see that in Network tab
        configuration.setAllowedOrigins(Arrays.asList("http:/url_1", "http:/url_2")); 
        configuration.setAllowedMethods(Arrays.asList("GET","POST"));
        configuration.setAllowedHeaders(Arrays.asList("content-type"));
        configuration.setAllowCredentials(true);
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and()...
    }
}

Method configure(HttpSecurity http) by default will use corsConfigurationSource for http.cors()

Pavel
  • 2,005
  • 5
  • 36
  • 68
6

If you're using .NET Core, you will have to .AllowCredentials() when configuring CORS in Startup.CS.

Inside of ConfigureServices

services.AddCors(o => {
    o.AddPolicy("AllowSetOrigins", options =>
    {
        options.WithOrigins("https://localhost:xxxx");
        options.AllowAnyHeader();
        options.AllowAnyMethod();
        options.AllowCredentials();
    });
});

services.AddMvc();

Then inside of Configure:

app.UseCors("AllowSetOrigins");
app.UseMvc(routes =>
    {
        // Routing code here
    });

For me, it was specifically just missing options.AllowCredentials() that caused the error you mentioned. As a side note in general for others having CORS issues as well, the order matters and AddCors() must be registered before AddMVC() inside of your Startup class.

Steven Pfeifer
  • 345
  • 4
  • 11
1

If it helps, I was using centrifuge with my reactjs app, and, after checking some comments below, I looked at the centrifuge.js library file, which in my version, had the following code snippet:

if ('withCredentials' in xhr) {
 xhr.withCredentials = true;
}

After I removed these three lines, the app worked fine, as expected.

Hope it helps!

Gustavo Garcia
  • 521
  • 5
  • 5
0

For me the issue was very simple, I had extention enabled in my chrome called Allow CORS: Access-Control-Allow-Origin and this extenion override headers and set Access-Control-Allow-Origin to * when when Allow CORS: Access-Control-Allow-Origin is exist in original response.

It take me 2 hours to find it, I hope it help somebody.

Ali Akbar Azizi
  • 3,272
  • 3
  • 25
  • 44