Skip to content

Instantly share code, notes, and snippets.

@kaji-bikash
Forked from algal/nginx-cors.conf
Last active August 29, 2015 14:06
Show Gist options
  • Select an option

  • Save kaji-bikash/c3483c483fc4919d8923 to your computer and use it in GitHub Desktop.

Select an option

Save kaji-bikash/c3483c483fc4919d8923 to your computer and use it in GitHub Desktop.

Revisions

  1. @algal algal created this gist Apr 29, 2013.
    230 changes: 230 additions & 0 deletions nginx-cors.conf
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,230 @@

    #
    # A CORS (Cross-Origin Resouce Sharing) config for nginx
    #
    # == Purpose
    #
    # This nginx configuration enables CORS requests in the following way:
    # - enables CORS just for origins on a whitelist specified by a regular expression
    # - CORS preflight request (OPTIONS) are responded immediately
    # - Access-Control-Allow-Credentials=true for GET and POST requests
    # - Access-Control-Max-Age=20days, to minimize repetitive OPTIONS requests
    # - various superluous settings to accommodate nonconformant browsers
    #
    # == Comment on echoing Access-Control-Allow-Origin
    #
    # How do you allow CORS requests only from certain domains? The last
    # published W3C candidate recommendation states that the
    # Access-Control-Allow-Origin header can include a list of origins.
    # (See: http://www.w3.org/TR/2013/CR-cors-20130129/#access-control-allow-origin-response-header )
    # However, browsers do not support this well and it likely will be
    # dropped from the spec (see, http://www.rfc-editor.org/errata_search.php?rfc=6454&eid=3249 ).
    #
    # The usual workaround is for the server to keep a whitelist of
    # acceptable origins on the server (as a regular expression), match
    # the request's Origin header against the list, and echo it back
    #
    # (Yes you can use '*' to accept all origins but this is too open and
    # prevents using 'Access-Control-Allow-Credentials: true', which is
    # needed for HTTP Basic Access authentication.)
    #
    # == Comment on spec
    #
    # Comments below are all based on my reading of the CORS spec as of
    # 2013-Jan-29 ( http://www.w3.org/TR/2013/CR-cors-20130129/ ), the
    # XMLHttpRequest spec (
    # http://www.w3.org/TR/2012/WD-XMLHttpRequest-20121206/ ), and
    # experimentation with latest versions of Firefox, Chrome, Safari at
    # that point in time.
    #
    # == Changelog
    #
    # based on https://gist.github.com/alexjs/4165271
    #

    location / {

    # if the request included an Origin: header with an origin on the whitelist,
    # then it is some kind of CORS request.

    # specifically, this example allow CORS requests from
    # scheme : http or https
    # authority : any authority ending in "mckinsey.com"
    # port : nothing, or :<any_number>
    if ($http_origin ~* (https?://.*\.mckinsey\.com(:[0-9]+)?)) {
    set $cors "true";
    }

    # Nginx doesn't support nested If statements, so we use string
    # concatenation to create a flag for compound conditions

    # OPTIONS indicates a CORS pre-flight request
    if ($request_method = 'OPTIONS') {
    set $cors "${cors}options";
    }

    # non-OPTIONS indicates a normal CORS request
    if ($request_method = 'GET') {
    set $cors "${cors}get";
    }
    if ($request_method = 'POST') {
    set $cors "${cors}post";
    }

    # if it's a GET or POST, set the standard CORS responses header
    if ($cors = "trueget") {
    # Tells the browser this origin may make cross-origin requests
    # (Here, we echo the requesting origin, which matched the whitelist.)
    add_header 'Access-Control-Allow-Origin' "$http_origin";
    # Tells the browser it may show the response, when XmlHttpRequest.withCredentials=true.
    add_header 'Access-Control-Allow-Credentials' 'true';
    # # Tell the browser which response headers the JS can see, besides the "simple response headers"
    # add_header 'Access-Control-Expose-Headers' 'myresponseheader';
    }

    if ($cors = "truepost") {
    # Tells the browser this origin may make cross-origin requests
    # (Here, we echo the requesting origin, which matched the whitelist.)
    add_header 'Access-Control-Allow-Origin' "$http_origin";
    # Tells the browser it may show the response, when XmlHttpRequest.withCredentials=true.
    add_header 'Access-Control-Allow-Credentials' 'true';
    # # Tell the browser which response headers the JS can see
    # add_header 'Access-Control-Expose-Headers' 'myresponseheader';
    }

    # if it's OPTIONS, for a CORS preflight request, then respond immediately with no response body
    if ($cors = "trueoptions") {
    # Tells the browser this origin may make cross-origin requests
    # (Here, we echo the requesting origin, which matched the whitelist.)
    add_header 'Access-Control-Allow-Origin' "$http_origin";
    # in a preflight response, tells browser the subsequent actual request can include user credentials (e.g., cookies)
    add_header 'Access-Control-Allow-Credentials' 'true';

    #
    # Return special preflight info
    #

    # Tell browser to cache this pre-flight info for 20 days
    add_header 'Access-Control-Max-Age' 1728000;

    # Tell browser we respond to GET,POST,OPTIONS in normal CORS requests.
    #
    # Not officially needed but still included to help non-conforming browsers.
    #
    # OPTIONS should not be needed here, since the field is used
    # to indicate methods allowed for "actual request" not the
    # preflight request.
    #
    # GET,POST also should not be needed, since the "simple
    # methods" GET,POST,HEAD are included by default.
    #
    # We should only need this header for non-simple requests
    # methods (e.g., DELETE), or custom request methods (e.g., XMODIFY)
    add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';

    # Tell browser we accept these headers in the actual request
    #
    # A dynamic, wide-open config would just echo back all the headers
    # listed in the preflight request's
    # Access-Control-Request-Headers.
    #
    # A dynamic, restrictive config, would just echo back the
    # subset of Access-Control-Request-Headers headers which are
    # allowed for this resource.
    #
    # This static, fairly open config just returns a hardcoded set of
    # headers that covers many cases, including some headers that
    # are officially unnecessary but actually needed to support
    # non-conforming browsers
    #
    # Comment on some particular headers below:
    #
    # Authorization -- practically and officially needed to support
    # requests using HTTP Basic Access authentication. Browser JS
    # can use HTTP BA authentication with an XmlHttpRequest object
    # req by calling
    #
    # req.withCredentials=true, and
    # req.setRequestHeader('Authorization','Basic ' + window.btoa(theusername + ':' + thepassword))
    #
    # Counterintuitively, the username and password fields on
    # XmlHttpRequest#open cannot be used to set the authorization
    # field automatically for CORS requests.
    #
    # Content-Type -- this is a "simple header" only when it's
    # value is either application/x-www-form-urlencoded,
    # multipart/form-data, or text/plain; and in that case it does
    # not officially need to be included. But, if your browser
    # code sets the content type as application/json, for example,
    # then that makes the header non-simple, and then your server
    # must declare that it allows the Content-Type header.
    #
    # Accept,Accept-Language,Content-Language -- these are the
    # "simple headers" and they are officially never
    # required. Practically, possibly required.
    #
    # Origin -- logically, should not need to be explicitly
    # required, since it's implicitly required by all of
    # CORS. officially, it is unclear if it is required or
    # forbidden! practically, probably required by existing
    # browsers (Gecko does not request it but WebKit does, so
    # WebKit might choke if it's not returned back).
    #
    # User-Agent,DNT -- officially, should not be required, as
    # they cannot be set as "author request headers". practically,
    # may be required.
    #
    # My Comment:
    #
    # The specs are contradictory, or else just confusing to me,
    # in how they describe certain headers as required by CORS but
    # forbidden by XmlHttpRequest. The CORS spec says the browser
    # is supposed to set Access-Control-Request-Headers to include
    # only "author request headers" (section 7.1.5). And then the
    # server is supposed to use Access-Control-Allow-Headers to
    # echo back the subset of those which is allowed, telling the
    # browser that it should not continue and perform the actual
    # request if it includes additional headers (section 7.1.5,
    # step 8). So this implies the browser client code must take
    # care to include all necessary headers as author request
    # headers.
    #
    # However, the spec for XmlHttpRequest#setRequestHeader
    # (section 4.6.2) provides a long list of headers which the
    # the browser client code is forbidden to set, including for
    # instance Origin, DNT (do not track), User-Agent, etc.. This
    # is understandable: these are all headers that we want the
    # browser itself to control, so that malicious browser client
    # code cannot spoof them and for instance pretend to be from a
    # different origin, etc..
    #
    # But if XmlHttpRequest forbids the browser client code from
    # setting these (as per the XmlHttpRequest spec), then they
    # are not author request headers. And if they are not author
    # request headers, then the browser should not include them in
    # the preflight request's Access-Control-Request-Headers. And
    # if they are not included in Access-Control-Request-Headers,
    # then they should not be echoed by
    # Access-Control-Allow-Headers. And if they are not echoed by
    # Access-Control-Allow-Headers, then the browser should not
    # continue and execute actual request. So this seems to imply
    # that the CORS and XmlHttpRequest specs forbid certain
    # widely-used fields in CORS requests, including the Origin
    # field, which they also require for CORS requests.
    #
    # The bottom line: it seems there are headers needed for the
    # web and CORS to work, which at the moment you should
    # hard-code into Access-Control-Allow-Headers, although
    # official specs imply this should not be necessary.
    #
    add_header 'Access-Control-Allow-Headers' 'Authorization,Content-Type,Accept,Origin,User-Agent,DNT,Cache-Control,X-Mx-ReqToken,Keep-Alive,X-Requested-With,If-Modified-Since';

    # build entire response to the preflight request
    # no body in this response
    add_header 'Content-Length' 0;
    # (should not be necessary, but included for non-conforming browsers)
    add_header 'Content-Type' 'text/plain charset=UTF-8';
    # indicate successful return with no content
    return 204;
    }
    }