[whatwg/fetch] Allow more flexibility in how 401s/407s are handled? (#1132)

About a year ago, I refactored how HTTP authentication prompts work in Chrome, and I recently learned (https://bugs.chromium.org/p/chromium/issues/detail?id=1159476) that this refactor is kind of incompatible with fetch() and Service Workers, specifically for main-frame main resources. Main resources have some special considerations when they trigger auth prompts, and it's not entirely clear how to make Chrome spec-compatible, so I wanted to start a discussion here. The tl;dr is that in Chrome we want to mitigate spoofing risks by not showing auth prompts for main resources mid-request, and this is at odds with what Fetch says.

For background, main resources are special when it comes to auth prompts because of the risk of user confusion/spoofing. If a user is navigating from a.com to b.com and the navigation triggers an auth prompt, the user might become confused and enter a.com credentials in the prompt, not realizing that they will be sent to b.com. Different browsers do different things about this risk:

- Firefox doesn't address this and will leave a.com in the address bar and in the content area, and show the b.com prompt on top of it.
![image](https://user-images.githubusercontent.com/602511/102922343-c0510e80-4442-11eb-8e60-a729fa7fe0ba.png)

- Safari appears to pause the navigation and put up a blank overlay interstitial and show the auth prompt on top of it. Chrome used to use this approach, but we moved away from it last year because it had lots of functional, security, and privacy [bugs](https://docs.google.com/document/d/1rEBpw5V-Nn1UIi8CIFa5ZZvwlR08SkY3CogvWE2UMFs/edit).

- With the new architecture, Chrome (and, I assume, Edge) cancels the request when it triggers an auth prompt, and commits a blank page and shows the auth prompt on top of it. Once the user enters credentials, the navigation is replayed with the credentials.

Belatedly, I now realize that Chrome's new approach violates the Fetch spec. Fetch says that when a network fetch results in a 401 or 407 response, the browser should prompt for credentials and then do another network fetch with those credentials and return that second network fetch as the response -- but Chrome doesn't want to show an auth prompt in the middle of a main resource fetch. This means that if a Service Worker intercepts a main resource fetch and passes the request into fetch(), it can receive a 401 or 407 response as the result, without the user being prompted for credentials. I'm hand-waving away some implementation details here, but I think the important point is that Fetch wants the browser to show an auth prompt mid-fetch, and Chrome explicitly wants to avoid doing that for main resources to implement a clear visual distinction between the old page and the new page.

I can't really think of a way to resolve these tensions -- adhering to Fetch while mitigating the spoofing risk while avoiding all the problems that overlay interstitials gave us -- hence I'm wondering if Fetch can give browsers more latitude in how they handle auth prompts by allowing browsers to return network errors if it's not safe to obtain credentials from the user at that moment:

- When handling 401s (step 11 of HTTP-network-or-cache fetch), the current algorithm doesn't give the browser any latitude to refuse to prompt. It could say something like "If appropriate, prompt the user for username and password; if not, return a network error" (borrowing the "if appropriate" language from the 407 handling below). This would be useful not just for main resource auth prompts, but in other situations where prompting might not be a good idea (Chrome blocks auth prompts from certain subresources, also to mitigate spoofing/confusion risks).
- When handling 407s (step 12 of HTTP-network-or-cache fetch), it could similarly say that a network error should be returned if not appropriate to prompt and no relevant proxy-authentication entries are stored.

Another option would be to return the 401/407 response directly (rather than a network error) if it's not safe to obtain credentials from the user, but I think (?) that is more likely to have compatibility issues with existing Service Workers, because existing Service Workers might accidentally cache 401/407 responses.

(As an aside, it seems to me that Fetch doesn't currently allow for the possibility that the user declines to enter credentials, e.g. cancels the authentication prompt, so these changes would also fix that, by allowing the browser to return a network error if credentials can't be obtained from the user.)

I'm happy to send PRs if these changes are amenable, but wanted to discuss first to see if there are other options I'm not seeing.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/whatwg/fetch/issues/1132

Received on Tuesday, 22 December 2020 20:05:45 UTC