Thursday, December 25, 2014

CORS

Here is my current thinking of how CORS basically works, which is enough for me to use it.

The CORS configuration is essentially a non-binding agreement between the client and the server.  It is up to the client to enforce the rules (CORS), and if the client wants to enforce those rules then it is up to the server to behave properly by providing a valid Access-Control-Allow-Origin header in responses which lists which origins that resource is intended for.
  • The domain name under which the JavaScript in the browser is executing is one origin.
  • The domain name under which the server is hosting the web service (with which that JS is interfacing) may be a different origin, or the JS may be hitting web services on multiple sites, and therefore multiple origins.
  • It is up to each web service to specify which origins they expect to be fielding requests from.

The server may be as lazy as possible by providing a wildcard Access-Control-Allow-Origin header:

Access-Control-Allow-Origin: *

Or it may be proper and provide the Access-Control-Allow-Origin head ONLY if the client presents an origin from the list configured on the server.

So, the way it works in practice is:
  1. The client calls the web service route with the OPTIONS method (rather than one of the more typical REST verbs: GET, PUT, POST, DELETE) and with the Origin header specifying the origin.  It might look like this:

            OPTIONS /hello HTTP/1.1
            User-Agent: curl/7.29.0
            Host: origin1.foo.com:10215
            Accept: */*
            Origin: http://origin2.foo.com
    

    As we can see here, the domain name presented in the Origin header (the name the client is running the JS code under) is different than the name in the Host header (where the JS has been instructed to make the web service call to).

    For reference, this request would be made using the curl command (for testing) like so:

            curl -vv -H "Origin: http://origin2.foo.com" -X OPTIONS http://origin1.foo.com:10215/hello
    

  2. If the server is configured for CORS and "http://origin2.foo.com" is in the list of configured origins for the /hello route, then the response from the server would be like this:

            HTTP/1.1 200 OK
            Server: nginx/1.6.2
            Date: Thu, 25 Dec 2014 23:00:49 GMT
            Content-Type: text/html; charset=utf-8
            Content-Length: 0
            Connection: keep-alive
            Allow: HEAD, GET, POST, OPTIONS
            Access-Control-Allow-Origin: http://origin2.foo.com
            Vary: Origin
    

  3. If the server is not configured for CORS, or if "http://origin2.foo.com" is not in the list of configured origins for the /hello route, the response from the server would be:

            HTTP/1.1 200 OK
            Server: nginx/1.6.2
            Date: Thu, 25 Dec 2014 23:23:03 GMT
            Content-Type: text/html; charset=utf-8
            Content-Length: 0
            Connection: keep-alive
            Allow: HEAD, GET, POST, OPTIONS
    

    Note here the lack of an Access-Control-Allow-Origin header, which indicates that the server is either not configured for CORS or the client provided an Origin value which was not in the list of configured origins for the /hello web service.

  4. If the server is configured for CORS, but is being as lazy as possible, the response from the server would be:

            HTTP/1.1 200 OK
            Server: nginx/1.6.2
            Date: Thu, 25 Dec 2014 23:23:03 GMT
            Content-Type: text/html; charset=utf-8
            Content-Length: 0
            Connection: keep-alive
            Allow: HEAD, GET, POST, OPTIONS
            Access-Control-Allow-Origin: *
    

    Note here the presence of the wildcard Access-Control-Allow-Origin header.