39
votes

What would cause Internet Explorer to replace the HTTP header

Authorization : Bearer <server-provided-token>

with

Authorization : Negotiate <some token>

when making an AJAX request?

Details

In Internet Explorer, some AJAX requests that are configured to contain the header Authorization: Bearer ... are being sent by Internet Explorer with the header Authorization: Negotiate ... instead.

For example, Fiddler shows that the first two of three requests contain the Authorization : Bearer... header, while the third suddenly contains the Authorization : Negotiate... header. The first two requests are successful, and the third fails because the request can't be properly authenticated.

All of the requests are constructed using the same client-side code, and are made one after another (within the span of a second). I have verified that the Authorization header correctly contains the Bearer token in all three cases up until the point the request is provided to the browser.

Also, I'm not seeing the same behavior in Chrome; it's only occurring in IE.

Request 1

GET http://localhost/myapp/api/User HTTP/1.1
Accept: application/json, text/plain, */*
Authorization: Bearer oEXS5IBu9huepzW6jfh-POMA18AUA8yWZsPfBPZuFf_JJxq-DKIt0JDyPXSiGpmV_cpT8FlL3D1DN-Tv5ZbT73MTuBOd5y75-bsx9fZvOeJgg04JcO0cUajdCH2h5QlMP8TNwgTpHg-TR9FxyPk3Kw6bQ6tQCOkOwIG_FmEJpP89yrOsoYJoCfrAoZ7M4PVcik9F9qtPgXmWwXB2eHDtkls44wITF_yM_rPm5C47OPCvMVTPz30KwoEPi6fHUcL3qHauP-v9uypv2e48TyPHUwLYmNFxyafMhBx4TkovnRcsdLHZiHmSjMq0V9a2Vw70
Referer: http://localhost/client/login.html
Accept-Language: en-US
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
Host: localhost
DNT: 1
Connection: Keep-Alive

Request 2

POST http://localhost/myapp/api/Permissions HTTP/1.1
Referer: http://localhost/client/#/Dashboard
Content-Type: application/json
Authorization: Bearer oEXS5IBu9huepzW6jfh-POMA18AUA8yWZsPfBPZuFf_JJxq-DKIt0JDyPXSiGpmV_cpT8FlL3D1DN-Tv5ZbT73MTuBOd5y75-bsx9fZvOeJgg04JcO0cUajdCH2h5QlMP8TNwgTpHg-TR9FxyPk3Kw6bQ6tQCOkOwIG_FmEJpP89yrOsoYJoCfrAoZ7M4PVcik9F9qtPgXmWwXB2eHDtkls44wITF_yM_rPm5C47OPCvMVTPz30KwoEPi6fHUcL3qHauP-v9uypv2e48TyPHUwLYmNFxyafMhBx4TkovnRcsdLHZiHmSjMq0V9a2Vw70
Accept: application/json, text/plain, */*
Accept-Language: en-US
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
Host: localhost
Content-Length: 1419
DNT: 1
Connection: Keep-Alive
Pragma: no-cache

<Post Data Removed>

Request 3

GET http://localhost/myapp/api/UserPreferences/Dashboard HTTP/1.1
Referer: http://localhost/client/#/Dashboard
Content-Type: application/json
Authorization: Negotiate YHsGBisGAQUFAqBxMG+gMDAuBgorBgEEAYI3AgIKBgkqhkiC9xIBAgIGCSqGSIb3EgECAgYKKwYBBAGCNwICHqI7BDlOVExNU1NQAAEAAACXsgjiBgAGADMAAAALAAsAKAAAAAYBsR0AAAAPVk1ERVZFTlYtU1JTQ0VSSVM=
Accept: application/json, text/plain, */*
Accept-Language: en-US
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
Connection: Keep-Alive
DNT: 1
Host: localhost

The requests are being made via the AngularJS $http service, and the back-end is ASP.NET Web API hosted in IIS.

6
Hi shrichards - did you ever figure this out? I seem to be encountering the same issue with IE 11.Joshua Barron
@JoshuaBarron I was never able to determine the root cause of the issue. I worked around the problem by creating a separate service with the single responsibility of issuing tokens. In IIS, that token service was configured to support both Windows and Anonymous authentication. The service that used the tokens for auth was then configured to use Anonymous authentication only in IIS (as auth was processed in via the tokens in the the middleware). This kept IE from attempting to perform integrated auth with IIS when the secured service was accessed.shrichards
Would you please give a more detailed example how you made this service (in github or pastebin). I lost more than two week with that problem and still can't find a work-around. Thanks in advance.Martin
Martin - I already had the same setup that shrichards describes. I followed bitoftech.net/2014/09/24/… to set this up. I still was encountering this issue for some requests that the client was making (see my linked question).Joshua Barron
I'm seeing this too and I'm looking for a good solution. Following this thread and will post if I find a solutionSam

6 Answers

21
votes

We had a problem where Internet Explorer was caching credentials. We could fix the problem by using the following script:

document.execCommand('ClearAuthenticationCache', 'false');

see: Wikipedia

6
votes

I've just come across this issue too.

What was odd is that it worked fine on my development machine, it was when I deployed it the issue arose. Again it worked fine in Chrome, Firefox etc.

It turns out that the issue is that IE was detecting the site was on the localintranet zone and was therefore trying to automatically trying log on (it was set by group policy - this is an internal app).

My workaround was that (luckily) it was only autodetecting local intranet zone when using a server name that wasn't an FQDN (e.g. myserver) - but using the full A

5
votes

I had the same problem in a knockoutjs application, it worked fine in Chrome and Firefox but not in IE.

I also used Fiddler and noticed that the first ajax call used Bearer as intended and returned successfully. But then IE started to loop and send the subsequent ajax calls over and over again with the Negotiate authorization instead!

In my case it was some sort of timing issue in IE, I solved it by making the ajax calls that loaded data during rendering synchronous.

    me.loadLimits = function () {
      $.ajax({
        type: 'GET',
        dataType: 'json',
        contentType: 'application/json',
        url: '/api/workrate/limits',
        headers: me.headers,
        async: false,
        success: function (result) {
    ...
4
votes

I also encountered this issue when I was kicking off multiple data loads in my angular app.

I worked around this by detecting the browser and if IE, delayed each request by 50ms based on the index of the call:

return $q(function(resolve, reject) {
 var delay = self.widget.useDelayLoading ? self.widget.index * 50 : 0;

 setTimeout(function() {
   restService.genericApi(self.widget.url, false).queryPost(json).$promise
    .then(
     function(r) { resolve(r); }, 
     function(e) { reject(e); }
    );
 }, delay);
});

Interestingly, when I used $timeout, I had to increase the delay to 100ms.

3
votes

We had faced similar issue with angular and web api. Issue happens when the system tries to access some resource at root level which had Windows Authentication enabled. In our case, application was trying to get the favicon from IIS root. Once this request gets unauthorized, IE will try getting the resouce with negotiation header; though it fails again. But from this point onwards, IE keep sending negotiate header instead of our bearer token. This is due to the settings in IE, which I think is in Internet Options -> Advanced tab -> Enable Integrated Windows Authentication in the Security section (not sure, I forgot the exact stuff).

Fix was either give anonymous access to root level or to the resource location which app is trying to access (bad option) or have document.execCommand('ClearAuthenticationCache', false); in the app.js file.

0
votes

In my case, IE alternated between sending a bad request, followed by a good request on a second attempt, then followed by a bad request again and so on.

After trying several approaches to causing IE to retry - it appears that returning a 307 (Temporary redirect) with the same request url in the Location header solves the issue.

e.g. for a request to "http://myUrl/api/service/"

HTTP 307 Temporary Redirect
Location: http://myUrl/api/service/

IE retries the call with the proper data.

Edit: This method might be dangerous as it might create an infinite loop. A possible solution to work around it, is to return some counter as part of the url in the Location header and analyze it when receiving the call again.