Skip to content

Instantly share code, notes, and snippets.

@rhfung
Forked from algal/nginx-cors.conf
Last active January 8, 2019 13:41
Show Gist options
  • Save rhfung/12fced0c159572f5207a2da5b6ecdab1 to your computer and use it in GitHub Desktop.
Save rhfung/12fced0c159572f5207a2da5b6ecdab1 to your computer and use it in GitHub Desktop.
nginx configuration for CORS (Cross-Origin Resource Sharing), with an origin whitelist, and HTTP Basic Access authentication allowed
#
# 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 (as a regular expression), match the request's
# Origin header against the list, and echo back the matched value.
#
# (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/algal/5480916
# based on: https://gist.github.com/michiel/1064640
# CORS
# specifically, this example allow CORS requests from
# scheme : http or https
# authority : any authority ending in ".mckinsey.com"
# port : nothing, or :
if ($http_origin ~* ((http|https)?://[^/]*\.newtechq\.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 ($request_method = 'PUT') {
set $cors "${cors}put";
}
if ($request_method = 'PATCH') {
set $cors "${cors}put";
}
if ($request_method = 'DELETE') {
set $cors "${cors}delete";
}
# if it's a GET, POST, PUT, DELETE, 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, besides the "simple response headers"
# add_header 'Access-Control-Expose-Headers' 'myresponseheader';
}
if ($cors = "trueput") {
# 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 = "truepatch") {
# 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 = "truedelete") {
# 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 it's OPTIONS, then it's a CORS preflight request so 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,PUT,DELETE,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, PUT, DELETE, OPTIONS';
# Tell browser we accept these headers in the actual request
# 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' 'Access-Control-Request-Method,Access-Control-Request-Headers,Cache,Pragma,Authorization,Accept,Accept-Encoding,Accept-Language,Host,Referer,Content-Length,Origin,DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
# 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;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment