IE: "Origin not found in Access-Control-Allow-Origin header" using CORS enabled .NET Core and Angular 2 - angularjs

I'm in the process of building an internal application where I am using Angular 2 (CLI/Webpack) to call a CORS enabled service that I built using .NET Core. The service uses the user's Integrated Windows Authentication credentials to look up information about that user and return it to Angular. Everything works fine in Chrome and Firefox, but in IE 10 and 11, I receive a "401 Unauthorized" response with the message Origin http://localhost:4200 not found in Access-Control-Allow-Origin header.
In Angular, I'm making an HTTP call like so:
private options = new RequestOptions({withCredentials: true});
let getURL = `server:port/api/users/username`;
return this.http
.get(getURL, this.options)
.map((response: Response) => response.json()[0])
.catch(this.handleError);
and my .NET Core service uses the following code in Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy("policyAnyone",
builder => {
builder.AllowCredentials()
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
});
});
services.AddApplicationInsightsTelemetry(Configuration);
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseCors("policyAnyone");
app.UseApplicationInsightsRequestTelemetry();
app.UseApplicationInsightsExceptionTelemetry();
app.UseMvc();
}
The controller then uses the username it receives via User.FindFirst(ClaimTypes.Name).Value, runs a stored procedure, and returns the results.
For reference, Chrome has the following request headers:
Accept: application/json, text/plain, `*/*`
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8
Authorization: Negotiate %lotsOfEncodedText%
Cache-Control: max-age=0
Connection: keep-alive
content-type: text/plain
Host: server:port
Origin: http://localhost:4200
Referer: http://localhost:4200/dashboard
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36
and IE has these:
Request: GET /api/users/username HTTP/1.1
Accept: application/json, text/plain, `*/*`
Content-Type: text/plain
Referer: http://localhost:4200/dashboard
Accept-Language: en-US
Origin: http://localhost:4200
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
Host: server:port
Connection: Keep-Alive
Cache-Control: no-cache
It seems as though CORS is configured correctly, and my Angular setup is pretty simple, but IE doesn't even display the credentials box.

In case anyone runs across this, I think I was able to solve the problem. My issue is with my PC's Internet Options where the Logon Authentication option (Internet Options > Security > Custom level... > User Authentication > Logon) was set to "Automatic logon only in Intranet zone". While this is intended, IE wasn't seeing my site as an intranet site, but rather an internet site. The reason for this is the "dot rule" that IE uses.
"If the URI’s hostname doesn’t contain any periods (e.g. http://team/) then it is mapped to the Local Intranet Zone." [1]
Our local site's hostname contains periods and is therefore mapped to the Internet Zone. After we are able to cut through the red tape, manually adding my site to the Local Intranet Zone (Internet Options > Security > Local Intranet > Sites > Advanced) should fix my issue.
I'm not sure why IE decided to respond with the CORS ACAO error message that it did, but the 401: Unauthorized response was at least enough to tip me off.
[1] Info on the Internet Option: https://support.microsoft.com/en-us/help/258063/internet-explorer-may-prompt-you-for-a-password
[2] Info on the Intranet Zone determination: https://blogs.msdn.microsoft.com/ieinternals/2012/06/05/the-intranet-zone/

IE treats ports differently than other browsers. Other browsers say that if the port is different, then it is not the same "origin". In IE, if the ports are different but the domain is the same, then it is same origin and the headers are not used.
You can read more here : https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy#IE_Exceptions
However you should still see the returned data via Angular (Since IE would just treat them as same origin). So are you seeing response data at all from your ajax call?

Related

http response not setting cookie in the browser

TLDR:
The following response header doesn't set the cookie in browser:
Access-Control-Allow-Origin: *
Allow: GET, HEAD, OPTIONS
Content-Length: 7
Content-Type: application/json
Date: Tue, 27 Apr 2021 15:58:02 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.9.4
Set-Cookie: csrftoken=r5r2YcZZvJKs79cbLd24VSyNscpUsxJB6UuWiWO2TXriy6B4r8KDZrwSDyI091K1; expires=Tue, 26 Apr 2022 15:58:02 GMT; Max-Age=31449600; Path=/; SameSite=Lax
Vary: Accept, Cookie, Origin
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
My request headers:
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8
Cache-Control: no-cache
Connection: keep-alive
Host: 127.0.0.1:8000
Origin: http://localhost:3000
Pragma: no-cache
Referer: http://localhost:3000/
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="90", "Google Chrome";v="90"
sec-ch-ua-mobile: ?0
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.85 Safari/537.36
I am new to Django, react and "http header" related stuff.
My django dev server runs at:
http://127.0.0.1:8000/
and my react dev server runs at:
http://127.0.0.1:3000
In order to access the website, login is required. So, all unauthorized requests are 1st redirected to login page, by configuring react-router and following this template. So, till now, no api calls are made.
In order to post login data, i need to have csrf token set by the server. But since i have not made any api calls, i created an endpoint /api/csrf/ explicitly, to set the csrf token.
# URL: /api/csrf/
class CSRFGet(APIView):
"""
Explicitly set csrf cookie
"""
#method_decorator(ensure_csrf_cookie)
def get(self, request):
return Response('hello')
I call this endpoint, when useProvideAuth hook is mounted.
function useProvideAuth() {
const [token, setToken] = useState(null);
const login = (username, password) => {
return axios.post(
'/auth/',
{
username: username,
password: password
})
.then(response => {
setToken(response.token)
})
}
useEffect(()=> {
axios.get(
'/csrf/'
)
},[])
return {
token,
login,
}
}
To retrieve and set this cookie, i followed the official Django docs. I also enabled CORS policy using django-CORS-headers allow all origins.
Now, when i make a request to any page, it redirects to login page, and i can see api/csrf/ responds with:
Set-Cookie: csrftoken=LgHo2Y7R1BshM4iPisi5qCXhdHyAQK7hD0LxYwESZGcUh3dXwDu03lORdDq02pzG; expires=Tue, 26 Apr 2022 06:29:23 GMT; Max-Age=31449600; Path=/; SameSite=Lax
But, the cookie is not set at all. Why is it so?
Is my approach for getting csrf cookie correct? Please let me know, if i am making any security vulnerability with this approach.
Could you try adding the following to the django-cors-headers configuration and retry?
CORS_ALLOW_CREDENTIALS = True
Also, please note that the above configuration would probably not work if you are allowing all origins. See this Mozilla documentation: Credential is not supported if the CORS header ‘Access-Control-Allow-Origin’ is ‘*’
If you face such error, I suggest setting:
CORS_ALLOWED_ORIGINS = [
"http://127.0.0.1:3000",
]
or something fancier like:
CORS_ALLOWED_ORIGIN_REGEXES = [
r"^http://127.0.0.1:[0-9]{1,4}$",
]
Finally, make sure that you are using a django-cors-headers version >= 3.5 since the 2 above configuration had different aliases back then.
Let me know if it works, I am very curious.
Turns out the issue was, i was using http://127.0.0.1:8000 to make api calls, where as my server was on http://localhost:8000. Because of this, host and origin, in my request headers didn't match the same domain.
Cookies can be allowed to be used under same domain, with different ports and subdomains, unlike Same-Origin policy, but cannot be used cross-domains.
In my case, I guess http://127.0.0.1:8000 & http://localhost:8000 were considered different domains, and thus the browser was not setting my cookie.
Thanks Anas Tiour, for stating about Allow-Credentials. I had tried that too, but still had no luck until i found out the actual reason.

React-call to "Asp.Net Core with identity server" gives CORS-errors

Ill try to keep this short to save digital rain forest. Please ask If I missed any details.
I have an "asp .net 3.1 core + react"-project template in VS, with built in Identity server. This works ok, but I now want to do my react project in a separate project. So I started a new create-react-app-project.
So, from my new react project, when I call OidcConfigurationController. The controller method is called and I can step through the code on server side. Then I get a client error "Failed to fetch", which, by internet wizdom, seems to indicated CORS-error.
This is what I got when I inspect the header in chrome dev toolbar->network
Request URL: https://localhost:5001/authentication/_configuration/MyProject.Web
Referrer Policy: strict-origin-when-cross-origin
:authority: localhost:5001
:method: GET
:path: /authentication/_configuration/MyProject.Web
:scheme: https
accept: */*
accept-encoding: gzip, deflate, br
accept-language: en-US,en;q=0.9,sv;q=0.8
origin: http://localhost:3000
referer: http://localhost:3000/
sec-ch-ua: "Google Chrome";v="87", " Not;A Brand";v="99", "Chromium";v="87"
sec-ch-ua-mobile: ?0
sec-fetch-dest: empty
sec-fetch-mode: cors
sec-fetch-site: cross-site
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
These are relevant lines in startup.cs
ConfigureServices()
services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
builder =>
{
//builder.WithOrigins("http://localhost:3002/", "https://localhost:3001")
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
});
});
services.AddSingleton<ICorsPolicyService>((container) => {
var logger = container.GetRequiredService<ILogger<DefaultCorsPolicyService>>();
return new DefaultCorsPolicyService(logger)
{
AllowAll = true
};
});
Configure()
app.UseCors(MyAllowSpecificOrigins); // I also tried to switch order on these 2 rows
app.UseIdentityServer();
Nothing I do here seems to change the Referrer Policy in the header, still get the exact same message
The React-call is just a plain fetch(address-of-the-controller-that-it-hits).
I have also tried to start a new Server Side-project (asp net core api) and set same CORS-policy, I can call this api from my react client without getting any errors)
So, in the request, you see the origin: http://localhost:3000 header is used. That is the source for the CORS request. But the request is for this URL:
https://localhost:5001/authentication/_configuration/MyProject.Web
Could it not be that there's a redirect from insecure HTTP to HTTPS that is interfering?
Do make sure you set the CORS settings in IdentityServer as well.
See the CORS documentation for more details.
As side note, IIS might cause CORS issues as well, see this answer for details:
IIS hijacks CORS Preflight OPTIONS request

Requests return 400 but not reaching server running on localhost (different behavior for different browsers)

I have server running on localhost:8080 (localhost:3000 request is redirected to localhost:8080 by proxy definition in package.json) and sending requests from ReactJS app to this server on localhost. In all browsers suddenlly started occuring this problem. Requests (except keepalive request and 1 or 2 others) return 400 but does not reach server at all. E. g. in Chrome it is happening for all requests but in Firefox a few requests return status code 200 and response with data without problem but other requests behave as mentioned above.
I am using Windows 10.
All browsers have problems: Chrome, Firefox, IE, Edge, Opera, Chromium
I tried turning off defender firewall and AVG.
Request examples:
Chrome
Request URL: http://localhost:3000/api/essp/database?pageSize=1000
Request Method: GET
Status Code: 400 Bad Request
Request Headers:
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: cs-CZ,cs;q=0.9
authorization: Bearer (token hidden for privacy reasons)
authorizationjwt: Bearer (token hidden for privacy reasons)
Connection: keep-alive
content-type: application/json
Cookie: _ga=GA1.1.1056630521.1566899267
Host: localhost:3000
Referer: http://localhost:3000/systematic-evidence
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36
Same request but in Firefox
Request URL: http://localhost:3000/api/essp/database?pageSize=1000
Request Method: GET
Status Code: 200 OK
Request Headers:
Accept
*/*
Accept-Encoding
gzip, deflate
Accept-Language
cs,sk;q=0.8,en-US;q=0.5,en;q=0.3
Authorization
Bearer (token hidden for privacy reasons)
Authorizationjwt
Bearer (token hidden for privacy reasons)
Connection
keep-alive
Content-Type
application/json
Cookie
_ga=GA1.1.647499021.1563197779
Host
localhost:3000
Referer
http://localhost:3000/systematic-evidence
User-Agent
Mozilla/5.0 (Windows NT 10.0; …) Gecko/20100101 Firefox/68.0
Different request in Firefox (400 is returned also in Chrome for this request)
Request URL: http://localhost:3000/api/essp/database/136adc97-75f7-4235-a48f-32e01c0f6add
Request Method: GET
Status Code: 400 Bad Request
Request Headers:
Accept
*/*
Accept-Encoding
gzip, deflate
Accept-Language
cs,sk;q=0.8,en-US;q=0.5,en;q=0.3
Authorization
Bearer (token hidden for privacy reasons)
Authorizationjwt
Bearer (token hidden for privacy reasons)
Connection
keep-alive
Content-Type
application/json
Cookie
_ga=GA1.1.647499021.1563197779
Host
localhost:3000
Referer
http://localhost:3000/systemat…97-75f7-4235-a48f-32e01c0f6add
User-Agent
Mozilla/5.0 (Windows NT 10.0; …) Gecko/20100101 Firefox/68.0
I am not BE developer but I was told it is not problem on server (on localhost), it is just something in my computer.
What could be causing this problem? Could it be something in Windows or some application intervenes to requests and returns 400 without reaching server? How am I able to find out or solve this problem?
Thanks for any helpfull answer
EDIT:
Not CORS problem because requests returning 400 are not reaching server at all. And also some non-simple requests return 200 without problem in few browsers (e. g. Firefox).
SOLUTION:
Solved by restoring Windows to factory settings.

In react, how do I pass backend REST APIs to my frontend?

Pretty noobish question here, I do not wish to draw flak.
I have my frontend created with create-react-app and I'm using fetch to pass in the backend APIs to my frontend. The backend is running on localhost:8080 on the same machine as the frontend. Frontend is running on port 3000. I have hardcoded the URLs as "http://localhost:8080/getForm" and so on. It all works fine if I access the frontend on the same machine as it is hosted. However, if I access the frontend from a different machine, the API calls fail, which would make sense because the calls are being made to localhost.
Now, what would be the best approach to pass in machine-independent rest URLs? I do not want to set a static IP for my backend. I have tried:
Making a production build and bundling it with the backend. This again makes calls to localhost on the accessing machine, which fails.
Manipulating the URL with window.location.hostname+"getForm". This fails when I have different servers hosting frontend and backend.
Edit*
Okay, I managed to add a proxy to the node server by adding the following line to package.json.
"proxy":"http://localhost:8080/"
This forwards something like localhost:3000/api/getForm on the frontend to localhost:8080/api/getForm on the backend. This works pretty well, but now I am stuck on an issue which I presume is due to incorrect CORS setting. Proxied GET requests to the backend, which is a Spring Boot API, work fine, but proxied POST requests return a 403, with the response "Invalid CORS request".
I have added a #CrossOrigin(origins="http://localhost:3000") to the class-level of my spring application which should make all the apis CORS friendly. Also, I am using fetch on the frontend to make calls. Any leads on what I might be getting wrong?
POST /api/post HTTP/1.1
Host: localhost:3000
Connection: keep-alive
Content-Length: 22
Origin: http://localhost:3000
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36
Content-Type: application/json
Accept: /
Referer: http://localhost:3000/
Accept-Encoding: gzip, deflate, br
Accept-Language: en-IN,en-GB;q=0.9,en-US;q=0.8,en;q=0.7
Body - {"title":"abc","body":"def"}
Response - 403, Invalid CORS request
GET /api/get HTTP/1.1
Host: localhost:3000
Connection: keep-alive
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36
Accept: /
Referer: http://localhost:3000/
Accept-Encoding: gzip, deflate, br
Accept-Language: en-IN,en-GB;q=0.9,en-US;q=0.8,en;q=0.7
Response - 200, [{"id":1,"title":"Post 1","body":"Backend is connected fine and dandy!"}]
When you dont serve your code using node, you can use webpack to add globals, but then you need to create separate build for each environment.
When using Node with SSR:
What I usually do is use a .env file with specific constants for hostname, port, .. and use those in a js config file. Then you can import that js file and use it for your fetch calls. You can use dotenv (https://www.npmjs.com/package/dotenv) for adding the .env variables to your node process.
config file:
const config = {
env: {
host: (envConfig && envConfig.API_HOST) || 'localhost',
port: (envConfig && envConfig.API_PORT) || '8000',
httpOrigin: (envConfig && envConfig.API_PROTOCOL) || 'http'
}
}
export default config;
.env file:
API_PROTOCOL=https
API_HOST=localhost
API_PORT=8000
To transfer the config to the frontend you can seriablize in the the body of your html and pick it up on your client side render.
<script dangerouslySetInnerHTML={{ __html: `window.__envConfig=${serialize(envConfig)};` }} charSet="UTF-8"/>

Internet Explorer 11 replaces Authorization header

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.
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
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
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) {
...
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.
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.
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.

Resources