W3C home > Mailing lists > Public > public-webappsec@w3.org > May 2013

Re: Fetch: HTTP authentication and CORS

From: Hallvord Reiar Michaelsen Steen <hallvord@opera.com>
Date: Mon, 06 May 2013 19:45:06 +0200
To: "WebAppSec WG" <public-webappsec@w3.org>, "WebApps WG" <public-webapps@w3.org>, "Anne van Kesteren" <annevk@annevk.nl>
Message-ID: <515d163925cb8789c216b8e4a560ca1c@opera.com>
> I had a discussion with Hallvord on IRC about the exact semantics we
> want for HTTP authentication in the context of CORS (and in particular
> for XMLHttpRequest, though it would also affect e.g. <img
> crossorigin>).

So me and Anne have been going a bit back and forth on IRC, we agree on some stuff and disagree on other points - and we fundamentally agree that some implementor review and input would be valuable to really settle a conclusion on how this murky little intersection of specs should work..

So the basic issue is HTTP authentication (cached and/or supplied by JS) with XHR, and its interaction with CORS and other stuff like the anonymous flag and withCredentials.

> Username/password can be passed via open() or the URL. In that case we
> first check if the server challenges us (do a request without

> Authorization that results in a response with status 401).

So far I agree :)

> For CORS, we'd return to the caller right there.

Here I don't agree anymore. If I want to retrieve a HTTP auth-protected resource with XHR from a CORS-enabled server, the natural thing to do seems to try to pass in the user name and password in the XHR open() call. If the script author supplied user/pass and the server says 401 on a request without Authorization: surely the natural next step is to re-try with Authorization:?

Granted, my scenario takes a little bit more work before we reach this point: I think that if user/pass are supplied in open() or URL for a CORS request, the implementation must detect that the request requires preflight, and send "Access-Control-Request-Headers: Authorization" as part of that preflight.

Now, this is most definitely a corner case, me an Anne are both concerned about implementation complexity but we seem to draw different conclusions - I think that most of the infrastructure here is going to be in place already and making special XHR-CORS exceptions might be just as complex as implementing retry-with-Authorization, whereas I believe Anne thinks I'm prescribing too much complexity for too little gain. 
> If the Authorization header is set via setRequestHeader() we'd treat
> it as any other header. We assume the developer already checked if he
> was challenged or not, etc.

I agree with that :)
> If an Authorization header was cached for the URL in question

> (previous visit) we'd never reuse that under CORS.

This *might* be a case for withCredentials - but it doesn't make much sense given that a JS author can't be expected to know if there are cached credentials for some other site, so we've dropped that. However, most browsers prompt for user/pass if XHR (or IMG) requests are challenged - so we need a loophole that make sure the cached credentials from a request *triggered by* XHR *are* used (this is one place that gets overly complex - I'd definitely love to nuke the whole prompts-for-user/pass in response to JS/inlines misfeature. Anyone else agrees we can kill it without too much compat pain..?)
> I'd be great to know if there's consensus on this. General not caring works too.

Implementor views most welcome, including "I don't really care, either way works for us" :-)

BTW, here's a sort of (amateur) flow chart for what I'm proposing - after accepting some of Anne's feedback:

I just noticed I have omitted same-origin requests with anonymous flag set - if these get a 401 response we should probably go straight to "Done, content denied".

Hallvord R. M. Steen
Core tester, Opera Software
Received on Monday, 6 May 2013 17:45:07 UTC

This archive was generated by hypermail 2.4.0 : Friday, 17 January 2020 18:54:33 UTC