Avoid CORS requests for a React App
The Above is a typical way web apps are architected today.
The backend(api.example.com) is run on an entirely different machine and its API is exposed to be accessed by any type of frontend. We had our React frontend(app.example.com) whose development environment is built using webpack. The api calls are made using axios.
Because of this architecture, we end up having to make CORS requests to our own backend. Cross-origin resource sharing (CORS) is a mechanism that allows restricted resources on a web page to be requested from another domain outside the domain from which the first resource was served. There is an excellent document on Mozilla Developer Network that I recommend readers.
CORS is applied by all modern browsers. Our requests are stopped by the browser as they consider our site(app.example.com) to be trying to sent request to a separate origin(api.example.com) i.e our server.
Problem #1
The browser sents a pre-flight OPTIONS calls before any GET/POST requests, unless they are classified as simple requests.
In our app we had Authorization headers for most of our requests, which makes it a complex request and hence a pre-flight call will be sent to the domain from the browser. This caused a 401 (unauthorized) access to hold off our calls as the OPTIONS
request the browser was senting did not contain the authorization headers.
Soluion #1
If you’d like to send
Authorization
headers, your server had better be configured to allow it. Set your server up so it responds to anOPTIONS
request at that url with anAccess-Control-Allow-Headers: Authorization
header.
Problem #2
Response to preflight request doesn’t pass access control check: No ‘Access-Control-Allow-Origin’ header is present on the requested resource. Origin ‘http://localhost:3000' is therefore not allowed access. The response had HTTP status code 401.
Soluion #2
Access-Control-Allow-Origin: http://app.example.com
Both the solutions above required modifications to the server side for it to work, which was not possible for our case. Thus we tried a third solution
Solution #3
Install this chrome plugin which disables chromes CORS checking security.
This solved problem #2 but problem #1 was not solved. Also it is not wise to turn off CORS completely as this makes somes sites to malfucntion. Moreover the plugin wasnt updated since 2015 and it had a bug which didnt allow PATCH
requests. Thus we had to skip this plugin
Solution #4
Finally what we did was to route the requests from your App server(the one which serves up your built app and assets) which forwards it to the backend. And because the forwarded call is from server to server and not browser to server, we successfully avoid ALL pre-flight CORS requests!
Steps to route your calls to the backend through your app server:
Simply add a proxy
field to your package.json
, for example:
"proxy": "api.exampple.com",
So a call that was previously api.example.com/posts/post_id would become app.example.com/api/posts/post_id, which would then be forwarded to the backend route anyways.
Also make sure if your using axios to comment out your baseURL
//axios.defaults.baseURL =’api.example.com’
Keep in mind that proxy
only has effect in development (with npm start
), and it is up to you to ensure that URLs like point to the right thing in production.
The proxy
option supports HTTP, HTTPS and WebSocket connections.
If the proxy
option is not flexible enough for you, alternatively you can:
- Configure the proxy yourself
- Enable CORS on your server (here’s how to do it for Express).
- Use environment variables to inject the right server host and port into your app.
And that is all! Enjoy avoiding those nasty OPTIONS calls using the above option :)