title: Getting client-side CORS to work when provider rejects pre-flight requests due to missing authorization header
body: <p>I am developing an Angular app that'll be consuming SalesForce API's (a.k.a. a SalesForce "Connected App"). Authentication occurs via oAuth/OpenID and works well. However, the app cannot currently access the SalesForce API endpoints succesfully, because:</p>
  
  <ol>
  <li>It's a server-less app and REST calls are made client-side, <strong>AND</strong></li>
  <li>REST calls are "non-simple": they include custom headers (namely, the "Authorization" header which holds the oAuth access token), and thus cause the browser to issue a pre-flight OPTIONS request; <strong>AND</strong></li>
  <li>SalesForce rejects any API request that does not include a valid "Authorization" header and token, <strong>including the pre-flight</strong>, which by definition does not include the custom headers from the initial GET request (indeed the whole point of the pre-flight is to ask the server if it will allow the custom header in question).</li>
  </ol>
  
  <p>The client app URL has been added to the CORS origin whitelist in SalesForce setup, to no effect.</p>
  
  <p>This leaves me totally stuck. I can't avoid the pre-flight by removing the custom "Authorization" header from REST calls, because then the only way to transmit the oAuth token to the endpoints is in a URL parameter, which is not secure; I can't proxy the request through my own back-end (i.e., avoiding front-end CORS limitations) because it's a server-less app; and I can't make SalesForce accept the pre-flight because it's totally under the browser's control and there's no way to modify its headers.</p>
  
  <p>Is there a way to configure, or coerce, SalesForce to accept pre-flight OPTIONS requests without "Authorization" headers? If not, might there be some other way for me to get out of this catch 22?</p>
  
  <p><strong>Below is example code:</strong></p>
  
  <p>XHR request:</p>
  
  <pre><code>{
    "url": "https://test.salesforce.com/services/oauth2/userinfo",
    "body": null,
    "reportProgress": false,
    "withCredentials": false,
    "responseType": "json",
    "method": "GET",
    "headers": {
      "normalizedNames": [
        {
          "key": "accept",
          "value": "Accept"
        },
        {
          "key": "authorization",
          "value": "Authorization"
        }
      ],
      "lazyUpdate": null,
      "headers": [
        {
          "key": "accept",
          "value": ["application/json"]
        },
        {
          "key": "authorization",
          "value": ["Bearer [...]"] // OAuth token is here
        }
      ],
      "lazyInit": null
    },
    "params": {
      "updates": null,
      "cloneFrom": null,
      "encoder": { HttpUrlEncodingCodec },
      "map": null
    },
    "urlWithParams": "https://test.salesforce.com/services/oauth2/userinfo"
  }
  </code></pre>
  
  <p>Pre-flight request to <code>test.salesforce.com:443</code> resulting from the above:</p>
  
  <pre><code>OPTIONS /services/oauth2/userinfo HTTP/1.1
  Host: test.salesforce.com
  Connection: close
  Pragma: no-cache
  Cache-Control: no-cache
  Access-Control-Request-Method: GET
  Origin: [...] // client app URL is here
  User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36
  Access-Control-Request-Headers: authorization
  Accept: */*
  DNT: 1
  Accept-Encoding: gzip, deflate
  Accept-Language: en-US,en;q=0.9
  </code></pre>
  
  <p>Response to the pre-flight request:</p>
  
  <pre><code>HTTP/1.1 403 Forbidden
  Date: Fri, 22 Dec 2017 20:16:11 GMT
  Strict-Transport-Security: max-age=31536000; includeSubDomains
  X-Content-Type-Options: nosniff
  X-XSS-Protection: 1; mode=block
  Content-Security-Policy: upgrade-insecure-requests 
  Referrer-Policy: origin-when-cross-origin
  Cache-Control: no-cache,must-revalidate,max-age=0,no-store,private
  Set-Cookie: BrowserId=IBrO4jKqQ6qedsWA5DFIcw;Path=/;Domain=.salesforce.com;Expires=Tue, 20-Feb-2018 20:16:11 GMT;Max-Age=5184000
  Expires: Thu, 01 Jan 1970 00:00:00 GMT
  Connection: close
  Content-Length: 19
  
  Missing_OAuth_Token
  </code></pre>
  
  <p>Thanks so much in advance!</p>
  
  <p>P.S: this is the first question I've ever posted on StackOverflow. I hope it meets the standards. If it doesn't I apologize in advance and I'll be happy to modify.</p>