1347

Is there a way to allow multiple cross-domains using the Access-Control-Allow-Origin header?

I'm aware of the *, but it is too open. I really want to allow just a couple domains.

As an example, something like this:

Access-Control-Allow-Origin: http://domain1.example, http://domain2.example

I have tried the above code but it does not seem to work in Firefox.

Is it possible to specify multiple domains or am I stuck with just one?

sideshowbarker
  • 81,827
  • 26
  • 193
  • 197
Thomas J Bradley
  • 13,726
  • 3
  • 18
  • 8
  • 17
    [Rather than allowing a space-separated list of origins, (origin-list-or-null) is either a single origin or the string "null".](http://www.w3.org/TR/cors/#access-control-allow-origin-response-header) (thanks @maxpolk) – sam Oct 01 '13 at 01:30
  • 5
    Using the most recent Firefox, neither comma seperated, nor space seperated domains did work. Matching against a list of domains and putting a single host in the headers is still better security and does work properly. – Daniel W. Mar 26 '14 at 16:58
  • 2
    If you're struggling with this for HTTPS, I found a [solution](http://stackoverflow.com/questions/1653308/access-control-allow-origin-multiple-origin-domains/28552592#28552592). – Alex W Feb 17 '15 at 00:14
  • @sam or "*" ? `shared based by returning the value of the Origin request header, "*", or "null"` – Nate Anderson Sep 29 '17 at 22:45
  • 22
    **_important note_**: allowing only cretain domains in the `Access-Control-Allow-Origin` header does **not** mean that other domains cannot trigger a method on this endpoint (e.g. REST API method). It just means that disallowed origins cannot use the result in javascript (browser ensures this). For restricting access to an endpoint for specific domains use a server-side request filter that e.g. returns HTTP 401 for disallowed domains. – klues Nov 21 '18 at 12:41
  • 8
    You should always append `Vary: Origin` header when you want to use multiple URLs, see: https://fetch.spec.whatwg.org/#cors-protocol-and-http-caches – Null Jun 07 '19 at 20:30

35 Answers35

1044

Sounds like the recommended way to do it is to have your server read the Origin header from the client, compare that to the list of domains you would like to allow, and if it matches, echo the value of the Origin header back to the client as the Access-Control-Allow-Origin header in the response.

With .htaccess you can do it like this:

# ----------------------------------------------------------------------
# Allow loading of external fonts
# ----------------------------------------------------------------------
<FilesMatch "\.(ttf|otf|eot|woff|woff2)$">
    <IfModule mod_headers.c>
        SetEnvIf Origin "http(s)?://(www\.)?(google.com|staging.google.com|development.google.com|otherdomain.example|dev02.otherdomain.example)$" AccessControlAllowOrigin=$0
        Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
        Header merge Vary Origin
    </IfModule>
</FilesMatch>
roapp
  • 530
  • 6
  • 17
yesthatguy
  • 10,612
  • 1
  • 16
  • 4
  • How would you add wildcard subdomains like: `*.example.com` or wildcard ports like: `localhost:*` – Ben Winding Feb 23 '21 at 11:46
  • 7
    For anyone wondering you can do `(.+\.google.com)` instead of `(google.com|staging.google.com)` – Ben Winding Mar 17 '21 at 11:56
  • 2
    How would this behave if there is no match? Which would be the output of `Access-Control-Allow-Origin`? – Héctor Oct 24 '21 at 14:30
  • 7
    That regex is not well designed; in particular, insecure origins (using the `http` scheme) shouldn't be allowed, and DNS label separators should be escaped (`\.` instead of `.`); otherwise, an attacker could for instance buy the `developmentzgoogle.com` domain and mount cross-origin attacks from there. – jub0bs Dec 16 '21 at 09:38
  • @Héctor In such case it will just behave like this solution wasn't introduced at all - just will block all requests from non-matching domains. – biesior Sep 16 '22 at 07:52
283

Another solution I'm using in PHP:

$http_origin = $_SERVER['HTTP_ORIGIN'];

if ($http_origin == "http://www.domain1.com" || $http_origin == "http://www.domain2.com" || $http_origin == "http://www.domain3.com")
{  
    header("Access-Control-Allow-Origin: $http_origin");
}
Nikolay Ivanov
  • 5,159
  • 1
  • 26
  • 22
  • 5
    HTTP_ORIGIN is not reliable, see https://stackoverflow.com/questions/41231116/serverhttp-origin-doesnt-work – bareMetal Feb 10 '22 at 09:07
  • @bareMetal your comment is only partially correct. While it is true that there are cases where the [`Origin` HTTP header is `null`](https://stackoverflow.com/a/76180946/3673659), it is also important to note that this header is utilized in the default CORS mechanism for allowing or disallowing requests. The implementation mentioned here ensures strict matching (==) of specified origins and disallows requests when there is no match (i.e., `null` is considered a non-match). This approach is considered a safe implementation. – Advena Jun 26 '23 at 10:10
133

This worked for me:

SetEnvIf Origin "^http(s)?://(.+\.)?(domain\.example|domain2\.example)$" origin_is=$0 
Header always set Access-Control-Allow-Origin %{origin_is}e env=origin_is

When put in .htaccess, it will work for sure.

Patrick Mevzek
  • 10,995
  • 16
  • 38
  • 54
Jay Dave
  • 1,773
  • 1
  • 13
  • 9
96

I had the same problem with woff-fonts, multiple subdomains had to have access. To allow subdomains I added something like this to my httpd.conf:

SetEnvIf Origin "^(.*\.example\.com)$" ORIGIN_SUB_DOMAIN=$1
<FilesMatch "\.woff$">
    Header set Access-Control-Allow-Origin "%{ORIGIN_SUB_DOMAIN}e" env=ORIGIN_SUB_DOMAIN
</FilesMatch>

For multiple domains you could just change the regex in SetEnvIf.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Staugaard
  • 1,077
  • 7
  • 5
  • Handy to have an example for multiple domains: `^(https?:\/\/localhost:\d+)$|^(https?:\/\/.+\.yourdomain\.com)$` Here's it in action... https://regex101.com/r/GZHTLB/1 It's crazy gobbledegook but that regex101 site helps decipher it all. – chichilatte Sep 29 '21 at 09:49
78

Here's how to echo the Origin header back if it matches your domain with Nginx, this is useful if you want to serve a font multiple sub-domains:

location /fonts {
    # this will echo back the origin header
    if ($http_origin ~ "example.org$") {
        add_header "Access-Control-Allow-Origin" $http_origin;
    }
}
mjallday
  • 9,796
  • 9
  • 51
  • 71
53

For ExpressJS applications you can use:

app.use((req, res, next) => {
    const corsWhitelist = [
        'https://domain1.example',
        'https://domain2.example',
        'https://domain3.example'
    ];
    if (corsWhitelist.indexOf(req.headers.origin) !== -1) {
        res.header('Access-Control-Allow-Origin', req.headers.origin);
        res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
    }

    next();
});
eyecatchUp
  • 10,032
  • 4
  • 55
  • 65
38

Here is what i did for a PHP application which is being requested by AJAX

$request_headers        = apache_request_headers();
$http_origin            = $request_headers['Origin'];
$allowed_http_origins   = array(
                            "http://myDumbDomain.example"   ,
                            "http://anotherDumbDomain.example"  ,
                            "http://localhost"  ,
                          );
if (in_array($http_origin, $allowed_http_origins)){  
    @header("Access-Control-Allow-Origin: " . $http_origin);
}

If the requesting origin is allowed by my server, return the $http_origin itself as value of the Access-Control-Allow-Origin header instead of returning a * wildcard.

Patrick Mevzek
  • 10,995
  • 16
  • 38
  • 54
Rakib
  • 12,376
  • 16
  • 77
  • 113
  • 1
    Should probably check that `$request_headers['Origin'];` exists, otherwise any direct requests are going to trigger an E_NOTICE. – MrWhite Jan 12 '21 at 18:10
26

As mentioned above, Access-Control-Allow-Origin should be unique and Vary should be set to Origin if you are behind a CDN (Content Delivery Network).

Relevant part of my Nginx configuration:

if ($http_origin ~* (https?://.*\.mydomain\.com(:[0-9]+)?)) {
  set $cors "true";
}
if ($http_origin ~* (https?://.*\.my-other-domain\.com(:[0-9]+)?)) {
  set $cors "true";
}

if ($cors = "true") {
  add_header 'Access-Control-Allow-Origin' "$http_origin";
  add_header 'X-Frame-Options' "ALLOW FROM $http_origin";
  add_header 'Access-Control-Allow-Credentials' 'true';
  add_header 'Vary' 'Origin';
}
roapp
  • 530
  • 6
  • 17
hernvnc
  • 827
  • 11
  • 18
  • any `.` in the domain needs to be escaped, otherwise it matches any character. Also, you can have just one if statement instead of using a variable – suddjian Jun 29 '22 at 18:53
25

There is one disadvantage you should be aware of: As soon as you out-source files to a CDN (or any other server which doesn't allow scripting) or if your files are cached on a proxy, altering response based on 'Origin' request header will not work.

Mark
  • 267
  • 3
  • 2
25

For Nginx users to allow CORS for multiple domains. I like the @marshall's example although his anwers only matches one domain. To match a list of domain and subdomain this regex make it ease to work with fonts:

location ~* \.(?:ttf|ttc|otf|eot|woff|woff2)$ {
   if ( $http_origin ~* (https?://(.+\.)?(domain1|domain2|domain3)\.(?:me|co|com)$) ) {
      add_header "Access-Control-Allow-Origin" "$http_origin";
   }
}

This will only echo "Access-Control-Allow-Origin" headers that matches with the given list of domains.

Adriano Rosa
  • 8,303
  • 1
  • 25
  • 25
24

For multiple domains, in your .htaccess:

<IfModule mod_headers.c>
    SetEnvIf Origin "http(s)?://(www\.)?(domain1.example|domain2.example)$" AccessControlAllowOrigin=$0$1
    Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
    Header set Access-Control-Allow-Credentials true
</IfModule>
Patrick Mevzek
  • 10,995
  • 16
  • 38
  • 54
George
  • 6,006
  • 6
  • 48
  • 68
16

For IIS 7.5+ with URL Rewrite 2.0 module installed please see this SO answer

Community
  • 1
  • 1
Paco Zarate
  • 1,925
  • 1
  • 15
  • 13
16

Here's a solution for Java web app, based the answer from yesthatguy.

I am using Jersey REST 1.x

Configure the web.xml to be aware of Jersey REST and the CORSResponseFilter

<!-- Jersey REST config -->
<servlet>
  <servlet-name>JAX-RS Servlet</servlet-name>
  <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
  <init-param>
    <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
    <param-value>true</param-value>
  </init-param>
  <init-param>
    <param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
    <param-value>com.your.package.CORSResponseFilter</param-value>
  </init-param>
  <init-param>
    <param-name>com.sun.jersey.config.property.packages</param-name>
    <param-value>com.your.package</param-value>
  </init-param>
  <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
  <servlet-name>JAX-RS Servlet</servlet-name>
  <url-pattern>/ws/*</url-pattern>
</servlet-mapping>

Here's the code for CORSResponseFilter

import com.sun.jersey.spi.container.ContainerRequest;
import com.sun.jersey.spi.container.ContainerResponse;
import com.sun.jersey.spi.container.ContainerResponseFilter;


public class CORSResponseFilter implements ContainerResponseFilter{

    @Override
    public ContainerResponse filter(ContainerRequest request,
            ContainerResponse response) {
        
        String[] allowDomain = {"http://localhost:9000","https://my.domain.example"};
        Set<String> allowedOrigins = new HashSet<String>(Arrays.asList (allowDomain));                  
        
        String originHeader = request.getHeaderValue("Origin");
        
        if(allowedOrigins.contains(originHeader)) {
            response.getHttpHeaders().add("Access-Control-Allow-Origin", originHeader);
                        
            response.getHttpHeaders().add("Access-Control-Allow-Headers",
                    "origin, content-type, accept, authorization");
            response.getHttpHeaders().add("Access-Control-Allow-Credentials", "true");
            response.getHttpHeaders().add("Access-Control-Allow-Methods",
                    "GET, POST, PUT, DELETE, OPTIONS, HEAD");
        }
        
        return response;
    }
}
Michael
  • 8,362
  • 6
  • 61
  • 88
duvo
  • 1,634
  • 2
  • 18
  • 30
11

Maybe I am wrong, but as far as I can see Access-Control-Allow-Origin has an "origin-list" as parameter.

By definition an origin-list is:

origin            = "origin" ":" 1*WSP [ "null" / origin-list ]
origin-list       = serialized-origin *( 1*WSP serialized-origin )
serialized-origin = scheme "://" host [ ":" port ]
                  ; <scheme>, <host>, <port> productions from RFC3986

And from this, I argue different origins are admitted and should be space separated.

Patrick Mevzek
  • 10,995
  • 16
  • 38
  • 54
drAlberT
  • 22,059
  • 5
  • 34
  • 40
9

PHP Code:

$httpOrigin = isset($_SERVER['HTTP_ORIGIN']) ? $_SERVER['HTTP_ORIGIN'] : null;
if (in_array($httpOrigin, [
    'http://localhost:9000', // Co-worker dev-server
    'http://127.0.0.1:9001', // My dev-server
])) header("Access-Control-Allow-Origin: ${httpOrigin}");
header('Access-Control-Allow-Credentials: true');
Liakos
  • 512
  • 5
  • 10
8

I struggled to set this up for a domain running HTTPS, so I figured I would share the solution. I used the following directive in my httpd.conf file:

    <FilesMatch "\.(ttf|otf|eot|woff)$">
            SetEnvIf Origin "^http(s)?://(.+\.)?example\.com$" AccessControlAllowOrigin=$0
            Header set Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
    </FilesMatch>

Change example.com to your domain name. Add this inside <VirtualHost x.x.x.x:xx> in your httpd.conf file. Notice that if your VirtualHost has a port suffix (e.g. :80) then this directive will not apply to HTTPS, so you will need to also go to /etc/apache2/sites-available/default-ssl and add the same directive in that file, inside of the <VirtualHost _default_:443> section.

Once the config files are updated, you will need to run the following commands in the terminal:

a2enmod headers
sudo service apache2 reload
Alex W
  • 37,233
  • 13
  • 109
  • 109
  • I like this option and combined/modified it with the implementation that @George has. Sometimes servers don't have a2enmod available, so all you have to do is check your main httpd.conf to see if the line: LoadModule headers_module modules/mod_headers.so is uncommented. – Mike Kormendy Feb 26 '15 at 20:09
  • My origin had a port number, so I modified the regular expression to include that: `^http(s)?://(.+\.)?example\.com(:\d+)?$` – indiv May 01 '15 at 21:43
7

If you are having trouble with fonts, use:

<FilesMatch "\.(ttf|ttc|otf|eot|woff)$">
    <IfModule mod_headers>
        Header set Access-Control-Allow-Origin "*"
    </IfModule>
</FilesMatch>
noun
  • 3,635
  • 2
  • 25
  • 27
3

HTTP_ORIGIN is not used by all browsers. How secure is HTTP_ORIGIN? For me it comes up empty in FF.
I have the sites that I allow access to my site send over a site ID, I then check my DB for the record with that id and get the SITE_URL column value (www.yoursite.com).

header('Access-Control-Allow-Origin: http://'.$row['SITE_URL']);

Even if the send over a valid site ID the request needs to be from the domain listed in my DB associated with that site ID.

Community
  • 1
  • 1
mathius1
  • 1,381
  • 11
  • 17
3

Here's an expanded option for apache that includes some of the latest and planned font definitions:

<FilesMatch "\.(ttf|otf|eot|woff|woff2|sfnt|svg)$">
    <IfModule mod_headers.c>
        SetEnvIf Origin "^http(s)?://(.+\.)?(domainname1|domainname2|domainname3)\.(?:com|net|org)$" AccessControlAllowOrigin=$0$1$2
        Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
        Header set Access-Control-Allow-Credentials true
    </IfModule>
</FilesMatch>
Mike Kormendy
  • 3,389
  • 2
  • 24
  • 21
3

For a fairly easy copy / paste for .NET applications, I wrote this to enable CORS from within a global.asax file. This code follows the advice given in the currently accepted answer, reflecting whatever origin back is given in the request into the response. This effectively achieves '*' without using it.

The reason for this is that it enables multiple other CORS features, including the ability to send an AJAX XMLHttpRequest with the 'withCredentials' attribute set to 'true'.

void Application_BeginRequest(object sender, EventArgs e)
{
    if (Request.HttpMethod == "OPTIONS")
    {
        Response.AddHeader("Access-Control-Allow-Methods", "GET, POST");
        Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
        Response.AddHeader("Access-Control-Max-Age", "1728000");
        Response.End();
    }
    else
    {
        Response.AddHeader("Access-Control-Allow-Credentials", "true");

        if (Request.Headers["Origin"] != null)
            Response.AddHeader("Access-Control-Allow-Origin" , Request.Headers["Origin"]);
        else
            Response.AddHeader("Access-Control-Allow-Origin" , "*");
    }
}
QA Collective
  • 2,222
  • 21
  • 34
2

PHP code example for matching subdomains.

if( preg_match("/http:\/\/(.*?)\.yourdomain.example/", $_SERVER['HTTP_ORIGIN'], $matches )) {
        $theMatch = $matches[0];
        header('Access-Control-Allow-Origin: ' . $theMatch);
}
Patrick Mevzek
  • 10,995
  • 16
  • 38
  • 54
blak3r
  • 16,066
  • 16
  • 78
  • 98
2

To facilitate multiple domain access for an ASMX service, I created this function in the global.asax file:

protected void Application_BeginRequest(object sender, EventArgs e)
{
    string CORSServices = "/account.asmx|/account2.asmx";
    if (CORSServices.IndexOf(HttpContext.Current.Request.Url.AbsolutePath) > -1)
    {
        string allowedDomains = "http://xxx.yyy.example|http://aaa.bbb.example";

        if(allowedDomains.IndexOf(HttpContext.Current.Request.Headers["Origin"]) > -1)
            HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", HttpContext.Current.Request.Headers["Origin"]);

        if(HttpContext.Current.Request.HttpMethod == "OPTIONS")
            HttpContext.Current.Response.End();
    }
}

This allows for CORS handling of OPTIONS verb also.

Patrick Mevzek
  • 10,995
  • 16
  • 38
  • 54
Derek Wade
  • 697
  • 8
  • 11
1

Google's support answer on serving ads over SSL and the grammar in the RFC itself would seem to indicate that you can space delimit the URLs. Not sure how well-supported this is in different browsers.

Community
  • 1
  • 1
Bob Aman
  • 32,839
  • 9
  • 71
  • 95
  • 'serving ads over ssl' links to the spec http://www.w3.org/TR/cors/#access-control-allow-origin-response-header which adds a note, "In practice the origin-list-or-null production is more constrained. Rather than allowing a space-separated list of origins, it is either a single origin or the string "null". – spazm Apr 29 '15 at 19:09
  • While it's important to note that detail, when a specification says "In practice", it doesn't mean that it's only valid to do it that way. It means that if you do it that way, you may run into problems because the majority of implementors either implement the spec incorrectly or incompletely. The specification does allow for a space-separated list of origins, which you can see here in the EBNF under `origin-list`: http://tools.ietf.org/html/rfc6454#section-7.1 – Bob Aman May 04 '15 at 08:55
1

And one more answer in Django. To have a single view allow CORS from multiple domains, here is my code:

def my_view(request):
    if 'HTTP_ORIGIN' in request.META.keys() and request.META['HTTP_ORIGIN'] in ['http://allowed-unsecure-domain.com', 'https://allowed-secure-domain.com', ...]:
        response = my_view_response() # Create your desired response data: JsonResponse, HttpResponse...
        # Then add CORS headers for access from delivery
        response["Access-Control-Allow-Origin"] = request.META['HTTP_ORIGIN']
        response["Access-Control-Allow-Methods"] = "GET" # "GET, POST, PUT, DELETE, OPTIONS, HEAD"
        response["Access-Control-Max-Age"] = "1000"  
        response["Access-Control-Allow-Headers"] = "*"  
        return response
Silvain
  • 399
  • 4
  • 20
1

Only a single origin can be specified for the Access-Control-Allow-Origin header. But you can set the origin in your response according to the request. Also don't forget to set the Vary header. In PHP I would do the following:

/**
 * Enable CORS for the passed origins.
 * Adds the Access-Control-Allow-Origin header to the response with the origin that matched the one in the request.
 * @param array $origins
 * @return string|null returns the matched origin or null
*/
function allowOrigins($origins)
{
    $val = $_SERVER['HTTP_ORIGIN'] ?? null;
    if (in_array($val, $origins, true)) {
        header('Access-Control-Allow-Origin: '.$val);
        header('Vary: Origin');
        
        return $val;
    }
        
    return null;
}
    
if (allowOrigins(['http://localhost', 'https://localhost'])) {
   echo your response here, e.g. token
}
roapp
  • 530
  • 6
  • 17
Simon
  • 324
  • 1
  • 13
  • Perfect solution, it works well, I set the allowed origins in an array inside the functions because I have 6 origins to allow: `'capacitor://localhost', 'ionic://localhost', 'http://localhost', 'http://localhost:4200', 'http://localhost:8080', 'http://localhost:8100',` – Pierre May 04 '23 at 15:00
1

I have https://stackoverflow.com/a/7454204/13779574 this code worked well but gives an error when the user enters that page. I fixed this problem with this code.

if (isset($_SERVER['HTTP_ORIGIN'])) {
   $http_origin = $_SERVER['HTTP_ORIGIN'];
   if ($http_origin == "http://localhost:3000" || $http_origin == "http://api.loc/"){  
      header("Access-Control-Allow-Origin: $http_origin");
   }
}
Akbarali
  • 688
  • 7
  • 16
0

If you try so many code examples like me to make it work using CORS, it is worth to mention that you have to clear your cache first to try if it actually works, similiar to issues like when old images are still present, even if it's deleted on the server (because it is still saved in your cache).

For example CTRL + SHIFT + DEL in Google Chrome to delete your cache.

This helped me using this code after trying many pure .htaccess solutions and this seemed the only one working (at least for me):

    Header add Access-Control-Allow-Origin "http://google.com"
    Header add Access-Control-Allow-Headers "authorization, origin, user-token, x-requested-with, content-type"
    Header add Access-Control-Allow-Methods "PUT, GET, POST, DELETE, OPTIONS"

    <FilesMatch "\.(ttf|otf|eot|woff)$">
        <IfModule mod_headers.c>
            SetEnvIf Origin "http(s)?://(www\.)?(google.com|staging.google.com|development.google.com|otherdomain.com|dev02.otherdomain.net)$" AccessControlAllowOrigin=$0
            Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
        </IfModule>
    </FilesMatch>

Also note that it is widely spread that many solutions say you have to type Header set ... but it is Header add .... Hope this helps someone having the same troubles for some hours now like me.

AlexioVay
  • 4,338
  • 2
  • 31
  • 49
0

Below answer is specific to C#, but the concept should be applicable to all the different platforms.

To allow Cross Origin Requests from a web api, You need to allow Option requests to your Application and Add below annotation at controller level.

[EnableCors(UrlString,Header, Method)] Now the origins can be passed only a s string. SO if you want to pass more than one URL in the request pass it as a comma seperated value.

UrlString = "https://a.hello.com,https://b.hello.com"

0

i was also facing same problem. my client was on 9097,api gateway on 9098,microservice on .... Actually i was using spring cloud Api gateway
in my gateway yml file i had allowed crossorigin like-- ... allowedOrigins: "http://localhost:9097"

also in my microservice i was using @crossOrigin

when client sent request to api gateway, two "Access-Control-Allow-Origin" headers was coming in responce [one from api yml file and one from microservice @crossorigin] so browser blocked request

i solved it as--

    @Bean
public RouteLocator getRL(RouteLocatorBuilder builder) {
    
return  builder.routes()
    
        .route(p-> 
         "/friendlist","/guest/**"
                )
         .filters(f ->{
             //f.removeResponseHeader("Access-Control-Allow-Origin");
             //f.addResponseHeader("Access-Control-Allow-Origin","http://localhost:9097");
             f.setResponseHeader("Access-Control-Allow-Origin","http://localhost:9097");
             return f;
         })
        .uri("lb://OLD-SERVICE")
        
        
    ).build();      
}
0

For Laravel Framework you can specify the allowed domains, for example in the CORS middleware:

app/Http/Middleware/Cors.php

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;

class Cors
{
    public function handle($request, Closure $next)
    {
        $response = $next($request);

        if (!method_exists($response, 'header')) {
            return $response;
        }

        $allowedOrigins = [
            'http://localhost:8000',
            'http://localhost:8080',
            'https://app.example.com',
            'https://example.com',
        ];

        if (in_array($request->header('origin'), $allowedOrigins)) {
            $origin = $request->header('origin');
        } else {
            return $response;
        }

        return $response
            ->header('Access-Control-Allow-Origin', $origin)
            ->header('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE, OPTIONS')
            ->header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization')
            ->header('Access-Control-Max-Age', '86400');
    }
}

Or you can use an Origin request:

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;

class Cors
{
    public function handle($request, Closure $next)
    {
        $response = $next($request);

        if (!method_exists($response, 'header')) {
            return $response;
        }

        $origin = $request->header('origin');

        return $response
            ->header('Access-Control-Allow-Origin', $origin)
            ->header('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE, OPTIONS')
            ->header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization')
            ->header('Access-Control-Max-Age', '86400');
    }
}

Then register it in app/Http/Kernel.php

    protected $routeMiddleware = [
        ...
        'cors' => \App\Http\Middleware\Cors::class,
    ];
    

And finally, use whatever you need on any routes:

Route::group(['middleware' => ['auth', 'cors']], function () {
    ...
    Route::get('/profile', [ProfileController::class, 'index']);
});

Vyacheslav
  • 59
  • 5
0

IF Apache webserver AND security does not matter (for example, doing tutorials on localhost or using for testing or other security-irrelevant applications), add this to your .htaccess file to allow requests from any domain / origin:

Header Set Access-Control-Allow-Origin *
cssyphus
  • 37,875
  • 18
  • 96
  • 111
0

For SvelteKit, add hooks.server.ts to src folder with this content:

import type { Handle } from '@sveltejs/kit';

export const handle: Handle = async ({ resolve, event }) => {
    const response = await resolve(event);

    const allowedOrigins = ['https://domain1.com', 'https://domain2.com'];
    console.log('allowedOrigins', allowedOrigins);

    const requestOrigin = event.request.headers.get('origin');
    console.log('requestOrigin', requestOrigin);
    

    if (allowedOrigins.includes(requestOrigin)) {
        // Handle preflight OPTIONS requests
        if (event.request.method === 'OPTIONS') {
            return new Response(null, {
                headers: {
                    'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH, OPTIONS',
                    'Access-Control-Allow-Origin': requestOrigin,
                    'Access-Control-Allow-Headers': '*'
                }
            });
        }

        response.headers.set('Access-Control-Allow-Origin', requestOrigin);
    }

    return response;
};
Elron
  • 1,235
  • 1
  • 13
  • 26
0

Another solution with regex in PHP :

if (isset($_SERVER['HTTP_REFERER'])) {
  $allowedReferers = [$_SERVER['SERVER_NAME'], 'localhost', 'google.com'];
  $rgx_escape = implode('|', array_map(function($value) { return preg_quote($value, '/'); }, $allowedReferers));

  if (preg_match("/$rgx_escape/", $_SERVER['HTTP_REFERER'])) {
      header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_REFERER']);
  } else {
    http_response_code(403);
    exit;
  }
}

Asalan
  • 85
  • 2
  • 11
-3

We can also set this in Global.asax file for Asp.net application.

protected void Application_BeginRequest(object sender, EventArgs e)
    {

    // enable CORS
    HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "https://www.youtube.com");

    }
sudhansu63
  • 6,025
  • 4
  • 39
  • 52
-19

The answer seems to be to use the header more than once. That is, rather than sending

Access-Control-Allow-Origin: http://domain1.example, http://domain2.example, http://domain3.example

send

Access-Control-Allow-Origin: http://domain1.example
Access-Control-Allow-Origin: http://domain2.example
Access-Control-Allow-Origin: http://domain3.example

On Apache, you can do this in an httpd.conf <VirtualHost> section or .htaccess file using mod_headers and this syntax:

Header add Access-Control-Allow-Origin "http://domain1.example"
Header add Access-Control-Allow-Origin "http://domain2.example"
Header add Access-Control-Allow-Origin "http://domain3.example"

The trick is to use add rather than append as the first argument.

Patrick Mevzek
  • 10,995
  • 16
  • 38
  • 54
Ben C. Forsberg
  • 771
  • 6
  • 2
  • The trick looks promising, but it doesn't work in FF 3.6.13. What I observe is that two headers with the same name are joined into one, with values separated with a comma -- and it doesn't work, as OP posted. I observed the headers in LiveHTTPHeaders and FireBug. – pwes Feb 10 '11 at 12:38
  • 1
    See, when I did it, I did "Header set ..." rather than "Header add ..." - seems to work for me. Firefox 3.6.16 – B T Apr 04 '11 at 23:50
  • This is not allowed and does not work in FF - https://bugzilla.mozilla.org/show_bug.cgi?id=671608 – Sairam Aug 27 '12 at 18:38
  • 2
    there's a variation on this which seems to work: http://stackoverflow.com/questions/9466496/how-to-configure-apache-to-handle-multiple-domains-with-access-control-allow-ori – Jack James Apr 28 '13 at 07:58
  • 123
    Just spent two hours trying to fix an issue related to CORS and it turns out that it was because of multiple Access-Control-Allow-Origin headers. I removed the multiple Access-Control-Allow-Origin headers and it started working. So this is not the right answer despite the number of votes. Use this method instead to support multiple domains: http://stackoverflow.com/a/1850482/123545 – ErJab May 25 '13 at 00:26
  • You will in fact get an error message in the log from the latest Chrome browser as of now, telling you that it's ignoring the Access-Control-Allow-Origin header because there are multiple values. – Danger Apr 24 '14 at 23:33
  • 1
    Nope. From https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS : "A returned resource may have one Access-Control-Allow-Origin header" .. and from http://www.w3.org/TR/cors/#access-control-allow-origin-response-header : "Rather than allowing a space-separated list of origins, it is either a single origin or the string "null"" (first I've heard of "null" here btw) – AlexChaffee Jun 10 '14 at 17:36
  • 23
    The [specs](http://www.w3.org/TR/cors/) clearly say that multiple values will cause the CORS algorithm to fails. So this isn't correct. – Lior Sep 08 '14 at 15:56
  • 10
    Also confirming this is incorrect. Using this to serve CSS to four domains, I receive an error in Chrome's log *"[...] header contains multiple values 'http://aaa.com, http://bbb.com', but only one is allowed"*. It does not matter if you define it as one header, or multiple, or using `add` vs. `set`. It just doesn't work. – Radley Sustaire Oct 08 '14 at 17:56