29

I am looking for a nginx config setup that does setup the Access-Control-Allow-Origin to the value received in the Origin.

It seems that the * method doesn't work with Chrome and the multiple URLs doesn't work with Firefox as it is not allowed by CORS specification.

So far, the only solution is to setup the Access-Control-Allow-Origin to the value received in the origin (yes some validation could be implemented).

The question is how to do this in nginx, preferably without installing additional extensions.

set $allow_origin "https://example.com"
# instead I want to get the value from Origin request header
add_header 'Access-Control-Allow-Origin' $allow_origin;
Walf
  • 8,535
  • 2
  • 44
  • 59
sorin
  • 161,544
  • 178
  • 535
  • 806
  • 1
    Chrome should most definitely work with `Access-Control-Allow-Origin: *`. Can you provide an example of the failing request/response headers? This might help as well: https://gist.github.com/4165271 – monsur Jan 24 '13 at 16:02
  • 1
    Yep, def works in Chrome with * and we were using it for a while now - here the link to my config https://distinctplace.com/2017/04/17/nginx-access-control-allow-origin-cors/ – gansbrest Apr 17 '17 at 21:25

3 Answers3

47

Using if can sometimes break other config such as try_files. You can end up with unexpected 404s.

Use map instead

map $http_origin $cors_header {
    default "";
    "~^https?://[^/]+\.example\.com(:[0-9]+)?$" "$http_origin";
}

server {
    ...
    location / {
        add_header Access-Control-Allow-Origin $cors_header;
        try_files $uri $uri/ /index.php;
    }
    ...
 }

If is evil

Community
  • 1
  • 1
phylae
  • 973
  • 1
  • 10
  • 18
  • 1
    `$http_origin` seems to be empty in my case, any ideas? – Toskan Dec 12 '18 at 20:22
  • @Toskan Where did the request come from? Most modern browsers will set the Origin header if you follow the recommended steps for a CORS XHR request. But if you use curl or just navigate to a web page, I don't think on Origin header is set by the browser. – phylae Dec 13 '18 at 21:43
  • @phylae actually I misunderstood the whole point. I thought I can set a http request header serving my homepage and thus allowing access to a third party. E.g. you go on myhomepage.com, I server CORS header with allowing access to someexternalapi.com. But as I finally see its the other way around. someexternalapi.com needs to server that header. – Toskan Dec 13 '18 at 21:51
  • YESSSSSSS finally – JacobIRR Feb 04 '22 at 21:49
25

I'm starting to use this myself, and this is the line in my current Nginx configuration:

add_header 'Access-Control-Allow-Origin' "$http_origin";

This sets a header to allow the origin of the request as the only allowed origin. So where ever you are coming from is the only place allowed. So it shouldn't be much different than allowing "*" but it looks more specific from the browser's perspective.

Additionally you can use conditional logic in your Nginx config to specify a whitelist of hostnames to allow. Here's an example from https://gist.github.com/Ry4an/6195025

if ($http_origin ~* (whitelist\.address\.one|whitelist\.address\.two)$) {
  add_header Access-Control-Allow-Origin "$http_origin";
}

I plan to try this technique in my own server to whitelist the allowed domains.

Mnebuerquo
  • 5,759
  • 5
  • 45
  • 52
  • 4
    If you have pages on multiple hosts which require access to the CORS resource, you will have problems if you are not using *. By specifying an origin, you lock that resource in your cache to the first page requesting it. Later requests from other pages will hit that cached page which allows the wrong origin. They will fail to load, even though your whitelist would allow them. http://stackoverflow.com/questions/21104810/what-could-explain-the-browser-intermittently-not-loading-some-cors-crossorigin?noredirect=1&lq=1 – Mnebuerquo Nov 29 '16 at 15:19
  • 3
    @Mnebuerquo The caching problem can be solved by adding $http_origin to the `cache_key`. Sending a `Vary: Origin` header should take care of client side caching. (Ie/edge seem to have problems with the Vary header though) – SleepProgger Nov 14 '17 at 14:30
1

Here is a part of a file from conf.f directory where people always describes their virtual hosts of Nginx. $http_origin compares with list of allowed_origins and then in second map block the system decides what will write to "header Access-Control-Allow-Origin" according to allowed list. Here is a part of code.

#cat /etc/nginx/conf.d/somehost.conf

map $http_origin $origin_allowed {
        default 0;
        https://xxxx.yyyy.com 1;
        https://zzz.yyyy.com 1;
}
map $origin_allowed $origin {
        default "";
        1 $http_origin;
}
    
server {
       server_name somehost.com;
    #...[skipped text]
    add_header Access-Control-Allow-Origin $origin always;
    #....[skipped text]
}

I test it om my servers. All works fine. Have a nice day & be healthy, Eugene.

  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Oct 14 '21 at 13:43
  • Please provide more context about how to use this. I suggest you to read [answer]. – Rojo Oct 14 '21 at 17:02