adaam
adaam

Reputation: 3706

Avoiding preflight OPTIONS requests with CORS

I am building an Angular app that interacts with an API built with ASP.NET Web API 2. I am using Basic Authentication by sending an Authorization header with each request that requires authentication:

Angular snippet:

$http.defaults.headers.common['Authorization'] = authHeader;

Request:

Accept:application/json, text/javascript
Accept-Encoding:gzip, deflate, sdch
Accept-Language:en-US,en;q=0.8
Access-Control-Max-Age:1728000
Authorization:Basic [base64 encoded credential couplet here]
Connection:keep-alive
DNT:1
Host: blah.com
Origin:http://localhost:9000
Referer:http://localhost:9000/
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/53

This all works OKAY, but a preflight OPTIONS request is sent with every GET or POST request. This is majorly impacting the perceived speed of the application. I have done lots of reading on CORS "Simple Requests" and it seems that in order to avoid the dreaded preflight OPTIONS request is to avoid adding any custom headers in my requests. I've tried lots of other stuff like sending a Content-Type of text/plain, but it seems that the Authorization header is the thing that is violating the CORS "Simple request" requirement.

So it seems that I may have to move the API over to use token based authentication/authorization. In order to avoid preflight requests, it seems that I will need to place the token in the query string. This is okay as it is only a small internal web app which will only be accessed by a couple of users anyway. I intend to implement caching on controller responses. As each request to an controller action will have a different token in the querystring based on the currently authenticated user, will this render cacheing useless?

So:

  1. How do I avoid preflight requests (using custom Authorization headers if at all possible)
  2. If 1.) is not possible, and I move to token based auth, will I be unable to cache API responses for controller actions
  3. What are the most widely used methods to avoid preflight requests but also to auth users securely?

n.b I know there are a couple of other threads on SO and elsewhere on the web regarding this, but none of them tend to provide a definitive answer on whether it is possible to avoid preflight requests for GETs and POSTs when using custom HTTP authorization headers.

Upvotes: 18

Views: 11548

Answers (2)

andy_roddam
andy_roddam

Reputation: 461

Another solution that seems to be working OK for me. Instead of setting up a proxy and needing to route to the same domain, it is possible to return the preflight request directly from nginx and therefore reducing the time required by the preflight request down to just a couple of milliseconds.

Here is a simple snippet that can be used with nginx.

 location / {
    if ($request_method = 'OPTIONS') {
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Credentials' 'true';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization';
        add_header 'Access-Control-Max-Age' 1728000;
        add_header 'Content-Type' 'text/plain charset=UTF-8';
        add_header 'Content-Length' 0;
        return 204;
     }
}

Once the preflight request is successful, it is then possible to simple add "Access-Control-Allow-Origin" and other necessary stuff to the 'GET','POST' requests, etc...

Upvotes: 5

Reto
Reto

Reputation: 3141

I think this post (How to apply CORS preflight cache to an entire domain) pretty much says it all - there is not much you can do about this

The one simple solution is to add a reverse proxy to the proxy/webserver serving your angular app (e.g. nginx) to route your RESTful calls via the same domain, e.g. appdomain.com/api --> apidomain.com.

Upvotes: 10

Related Questions