title: AngularJS: OPTIONS preflight call preceding a $http.post request
body: <p>I'm using AngularJS v1.2.4.</p>
  
  <p>I had an issue with Angular sending a preflight OPTIONS call (Chrome was showing the OPTIONS call as 'canceled') and resolved it with:</p>
  
  <pre><code>$httpProvider.defaults.useXDomain = true;
  delete $httpProvider.defaults.headers.common['X-Requested-With'];
  </code></pre>
  
  <p>That worked for all my $resource calls, and everything was good.</p>
  
  <p>Now I'm trying to implementation authentication, and a login page that sends a POST request to my server with the user's credentials. I'm seeing the problem I was facing before, but $resource calls are still working fine.</p>
  
  <p>What's really frustrating is that the problem happens intermittently; I'll change a few options surrounding the headers, then it'll work for a bit, and stop working again without any code change.</p>
  
  <p>My server is configured for CORS and works fine with curl, and other REST clients. Here's an example:</p>
  
  <pre><code>curl -X OPTIONS -ik 'https://localhost:3001/authenticate' -H "Origin: https://localhost:8001"
  HTTP/1.1 200 OK
  content-type: application/json; charset=utf-8
  content-length: 2
  cache-control: no-cache
  access-control-allow-origin: *
  access-control-max-age: 86400
  access-control-allow-methods: GET, HEAD, POST, PUT, DELETE, OPTIONS
  access-control-allow-headers: Authorization, Content-Type, If-None-Match, Access-Control-Allow-Headers, Content-Type
  access-control-expose-headers: WWW-Authenticate, Server-Authorization
  set-cookie: session=Fe26.2**94705d49717d1273197ae86ce6661775627d7c6066547b757118c90c056e393b*2KYqhATojPoQhpB2OwhDwg*W9GsJjK-F-UPqIIHTBHHZx1RXipo0zvr97_LtTLMscRkKqLqr8H6WiGd2kczVwL5M25FBlB1su0JZllq2QB-9w**5510263d744a9d5dc879a89b314f6379d17a39610d70017d60acef01fa63ec10*pkC9zEOJTY_skGhb4corYRGkUNGJUr8m5O1US2YhaRE; Secure; Path=/
  Date: Wed, 18 Dec 2013 23:35:56 GMT
  Connection: keep-alive
  </code></pre>
  
  <p>Here's the $http.post call:</p>
  
  <pre><code>var authRequest = $http.post('https://' + $location.host() + ':3001/authenticate', {email: email, password: password});
  </code></pre>
  
  <p>When the call from my app works, this is how the OPTIONS request looks like:</p>
  
  <p><img src="https://i.stack.imgur.com/JMGjh.png" alt="enter image description here"></p>
  
  <p>When it doesn't work, this is the OPTIONS request: </p>
  
  <p><img src="https://i.stack.imgur.com/fse6d.png" alt="enter image description here"></p>
  
  <p>It looks like a whole bunch of header attributes are missing. Has anyone encountered a similar issue?</p>
  
  <p>Edit:</p>
  
  <p>Just to clarify, when it doesn't work, the request never makes it to the server - it's instantly aborted in the browser.</p>
  
  <p><img src="https://i.stack.imgur.com/1eqLP.png" alt="enter image description here"></p>
  
  <p>In Firebug, the request headers are:</p>
  
  <pre><code>OPTIONS /authenticate HTTP/1.1
  Host: localhost:3001
  User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:25.0) Gecko/20100101 Firefox/25.0
  Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
  Accept-Language: en-US,en;q=0.91,en-GB;q=0.82,fr-FR;q=0.73,fr;q=0.64,utf-8;q=0.55,utf;q=0.45,de-DE;q=0.36,de;q=0.27,en-sg;q=0.18,en-ca;q=0.09
  Accept-Encoding: gzip, deflate
  Origin: https://localhost:8001
  Access-Control-Request-Method: POST
  Access-Control-Request-Headers: content-type
  Proxy-Authorization: Basic cGF0cmljZUB6b25nLmNvbTpjaGFuZ2VtZQ==
  Connection: keep-alive
  Pragma: no-cache
  Cache-Control: no-cache
  </code></pre>
  
  <p><img src="https://i.stack.imgur.com/H4yAM.png" alt="enter image description here"></p>
  
  <p>Update:</p>
  
  <p>I've eliminated the possibly of a problem with the server, I think, by changing the host to a non-existent server. Still seeing the same behavior.</p>
  
  <p>Here's some code:</p>
  
  <pre><code>App.services.factory('AuthService', function ($http, $location, $q) {
  
      var currentUser;
  
      return {
          authenticate: function (email, password) {
  
              //promise to return
              var deferred = $q.defer();
  
              var authRequest = $http.post('https://this.does.not.exist.com:3001/authenticate', {email: email, password: password});
  
              authRequest.success(function (data, status, header, config) {
                  currentUser = data;
                  console.log('currentUser in service set to:');
                  console.log(currentUser);
                  //resolve promise
                  deferred.resolve();
              });
  
              authRequest.error(function (data, status, header, config) {
                  console.log('authentication error');
                  console.log(status);
                  console.log(data);
                  console.log(header);
                  console.log(config);
  
                  //reject promise
                  deferred.reject('authentication failed..');
              });
  
              return deferred.promise;
          },
          isAuthenticated: function () {
              return currentUser !== undefined;
          }
      };
  });
  </code></pre>
  
  <p>and HTTP Config:</p>
  
  <pre><code>App.config(['$httpProvider', function ($httpProvider) {
  
      $httpProvider.defaults.useXDomain = true;
      //$httpProvider.defaults.headers.common = {};
  
      console.log('logging out headers');
      console.log($httpProvider.defaults);
      console.log($httpProvider.defaults.headers.common);
      console.log($httpProvider.defaults.headers.post);
      console.log($httpProvider.defaults.headers.put);
      console.log($httpProvider.defaults.headers.patch);
      console.log('end logging out headers');
  
      $httpProvider.defaults.headers.common = {Accept: "application/json, text/plain, */*"};
      $httpProvider.defaults.headers.post = {"Content-Type": "application/json;charset=utf-8"};
  
      console.log('after: logging out headers');
      console.log($httpProvider.defaults.headers.common);
      console.log($httpProvider.defaults.headers.post);
      console.log($httpProvider.defaults.headers.put);
      console.log($httpProvider.defaults.headers.patch);
      console.log('after: end logging out headers');
  
      $httpProvider.interceptors.push(function ($location, $injector) {
          return {
              'request': function (config) {
  
                  console.log('in request interceptor!');
  
                  var path = $location.path();
                  console.log('request: ' + path);
  
                  //injected manually to get around circular dependency problem.
                  var AuthService = $injector.get('AuthService');
                  console.log(AuthService);
                  console.log(config);
  
                  if (!AuthService.isAuthenticated() &amp;&amp; $location.path() != '/login') {
                      console.log('user is not logged in.');
                      $location.path('/login');
                  }
  
                  //add headers
                  console.log(config.headers);
                  return config;
              }
          };
      });
  }]);
  </code></pre>