At Financial Engines, we have been developing our authentication and authorization
platform on cloud as part of our componentization efforts.
Since our API’s gets consumed by our SPA’s (Single Page Application’s), we had to
think about how are we going to handle CORS.
In general, handling CORS is quite easy. You can either enable it in your web servers
or enable it in your microservices. Enabling it in your web servers works quite well as you
can keep adding multiple microservices and no additional changes are required in each
web server. Handling it in backend works fine if you have only 1-2 microservices but
as you start to grow it really does not make a lot of sense to replicate the logic in
different backend services.
Other architecture which is quite popular in enterprises having distributed systems
is handling common concerns such as CORS, authentication etc. in a separate layer known as API gateways.
In API gateways such as apigee, mulesoft it’s quite easy to enable CORS as they are
true proxies which can read requests and modify responses in any way.
When it comes to AWS API gateway, things gets interesting! At least as of Q1 2018. AWS
API gateway handles simple CORS request by returning pre-configured hardcoded CORS
but there is no way to handle advanced CORS requests where browser requires specific
origin header from the backend.
In general, for advanced CORS requests where SPA’s sends cookies for cross domain
requests, browser’s expect allowed origin header to be same as origin header. If it’s
value is *, browsers fails CORS request and throws error.
AWS API gateway does not follow a true proxy model where response can be modified
purely on request parameters without backend magic. Hence, AWS API gateway can not
handle advanced CORS requests where browsers requires specific cors-allowed-origin header to be sent by server instead of *.
AWS documentations also states that in such a case, you have to handle CORS request in
Assuming you have lots of microservices exposed via AWS API gateway, CORS has to be
handled in each microservice which becomes pain in itself especially if you are
running different microservices in different languages. Only way in such a case is to
add the functionality in a common library and share it across microservices.
I hope, AWS makes some fundamental changes to address this and other similar needs. Best option would be to provide
ability to modify requests and responses like a true proxy
On high level, to handle CORS, you need to take following steps
- ensure OPTIONS requests returns appropriate CORS headers
- ensure each API call (successor failure) returns appropriate CORS headers
There is no cleaner way to handle this currently and hence following are the options available in AWS
- each microservice handles CORS
- one proxy handles CORS
- Avoid CORS
Below is the deployment architecture for each microservice handling CORS. Considering
you may already have authorization in place in AWS API via cognito, custom authorizer,
you need to make sure that OPTIONS request is unauthorized so that request can be
propagated to the backend.
Other option is introducing one additional layer which acts as proxy and handles
This layer could be Lambda or Elastic beanstalk app. This layer compliments AWS API
gateway but introduces its own latency and management overhead.
Interestingly, many companies are still able to avoid CORS. In such a scenario, each
new subdomain has to have reverse proxy server setup to proxy api requests.
Hope AWS makes some fundamental changes in the way AWS API gateway works.
Till then, Keep hacking!