CORS allows HTTP authentication without special credentials header opt-in, because you already need to opt-in to the HTTP authentication header.
We should be clearer about that somehow.
In particular, the distinction seems to be that if withCredentials is true and the user agent had previously visited the target URL and the user had authenticated that URL, the user agent could include credentials in the request and the server could use the special credentials header opt-in.
Whether that's actually implemented in practice as such is unclear. The ability to set custom request headers also muddles the waters a bit.
See also: https://github.com/whatwg/xhr/pull/4
The fetch function should look up a URI on the web and return the result, taking (basically) no other parameters, but supplying credentials as and when asked for them. Currently the code that calls XHR or fetch has to guess whether credentials are required.
If the credential flag is not set, then the fetch will fail if the resource being accessed happens to be one which is access controlled, for example by client cert.
If the credential flag *is* set, then the CORS algorithm blocks wildcard access-control-allow-origin * so the caller can't access any public data. "XMLHttpRequest cannot load https://www.w3.org/foo. A wildcard '*' cannot be used in the 'Access-Control-Allow-Origin' header when the credentials flag is true. Origin 'http://linkeddata.github.io' is therefore not allowed access."
Code libraries have to be able to be able to written to access arbitrary resources on the web, some protected, some public, without a side channel to guess which they are. fetch() should handle this internally without the caller having to worry about it.
Presumably one technique would be to try using credentials, wait until the fetch fails (currently with no error message as to why which is a massive pain) and then try toggling the credentials flag and trying again. Why should a calling library have to do that though? Seems broken, unless I have misunderstood.
You can do a request without credentials. If the reply from the server is a 401 you could do another request that includes credentials. fetch() supports that use case. But you need to write the code.
I think this is the matrix we need to consider for this bug:
1. User has/doesn't have authorization entry
2. Developer set/didn't set Authorization
3. Credentials mode is "include" / not "include"
4. User agent does/doesn't include authorization entry without challenge.
The specification is probably wrong on 2 and it's unclear whether 4 is a thing.