This explanation on youtube is very helpful. One common misunderstanding about CORS is thinking of CORS as something that will cause a server or Tyk to deny access to an API. It’s not, but it does give information back to a web browser so that the browser can decide not to call the API.
The goal of CORS
As an example, lets imagine someone has invented a very cute icon. They use it on their website by embedding a reference to its URL in their html. A few months later they find that their icon has been downloaded a million times but their webpage which uses the icon has only been hit 100 times.
What's happened is that someone else has embedded the URL of the icon into their website's HTLM. That eats the bandwidth bandwidth of the first website.
This can be fixed with CORS (Cross Origin Resource Sharing). This is done by configuring the webserver to say that only people on the local website (the allowed origin) can access the file. A user’s browser will check the CORS headers from your website, letting your server know what website it’s currently on (the origin) and ask if it’s OK to grab the icon. The browser will read the reply and if things don’t match up it will give a CORS error. This is something the browser does, not the webserver. If the browser ignores CORS then the webserver can send all the CORS headers in the world but it won’t help. Similarly things like curl or postman will ignore CORS headers.
The Preflight Call, OPTIONS
The browser can call an API with the OPTIONS method before attempting the actual call. The OPTIONS method just returns the information about what things are allowed by CORS. The browser will remember the results and refuse to break the restrictions sent. Things like postman and curl just ignore them and send the request anyway. The result is that CORS issues are almost always encountered when browsers connect to APIs hosted on Tyk rather than other client tools.
How CORS is configured on Tyk
Up until Tyk 3.0.0, this was enough to get Tyk to send CORS headers but allow calls from any origin as seen below
From 3.0.0 onward, a bare wildcard like that isn’t permitted. This was because it was deemed a security risk by the library that Tyk uses for CORS, not in Tyk itself.
To achieve the same thing in versions of Tyk from 3.0.0, add allowed origins of ‘http://*’ and ‘https://*’ which will achieve the same thing. Here's an example:
But when using CORS it’s better to populate the allowed origin with the true allowed origins (the website URLS which are allowed to embed references to this resource).
Other Options
"Allowed headers" lists the headers which will be accepted by CORS. More documentation on this is at Mozilla docs
Tyk documentation about CORS is here. Note the "debug" option which enables debug output in the upstream CORS library. It can only be enabled directly in the API JSON and adds debug output from the CORS library into the Tyk gateway logs (not the analytics) which can be super helpful.
Testing with curl
Starting with this config in an API definition where the allowed origin is https://pete.com and the allowed methods are GET, POST and HEAD.
Here's the output of a curl request that meets these limitations. Note that both Origin and Access-Control-Request-Method headers must be sent to get a valid response to an OPTIONS request
$ curl -vX OPTIONS -H 'Origin: https://pete.com' \
-H 'Access-Control-Request-Method: GET' \
http://10.0.0.24:5005/cors-example/
* Trying 10.0.0.24:5005...
* Connected to 10.0.0.24 (10.0.0.24) port 5005
> OPTIONS /cors-example/ HTTP/1.1
> Host: 10.0.0.24:5005
> User-Agent: curl/8.5.0
> Accept: */*
> Origin: https://pete.com
> Access-Control-Request-Method: GET
>
< HTTP/1.1 204 No Content
< Access-Control-Allow-Methods: GET
< Access-Control-Allow-Origin: https://pete.com
< Access-Control-Max-Age: 24
< Vary: Origin, Access-Control-Request-Method, Access-Control-Request-Headers
< Date: Thu, 06 Feb 2025 12:15:45 GMT
<
* Connection #0 to host 10.0.0.24 left intact
The response populates these headers to tell the browser that it's happy to serve a GET request for this API embedded in the site https://pete.com
This next example tests if https://roguesite.com can do the same thing
$ curl -vX OPTIONS -H 'Origin: https://roguesite.com' \
-H 'Access-Control-Request-Method: GET' \
http://10.0.0.24:5005/cors-example/
* Trying 10.0.0.24:5005...
* Connected to 10.0.0.24 (10.0.0.24) port 5005
> OPTIONS /cors-example/ HTTP/1.1
> Host: 10.0.0.24:5005
> User-Agent: curl/8.5.0
> Accept: */*
> Origin: https://roguesite.com
> Access-Control-Request-Method: GET
>
< HTTP/1.1 204 No Content
< Vary: Origin, Access-Control-Request-Method, Access-Control-Request-Headers
< Date: Thu, 06 Feb 2025 12:27:14 GMT
<
* Connection #0 to host 10.0.0.24 left intact
In this case there are no Access-Control-Allow-* headers so this indicates a browser would report a CORS error if this request was attempted.
Comments
0 comments
Please sign in to leave a comment.