Simplified solution to CORS issues when calling an Ajax handler
posted 2020.06.25 by Clark Wilkins, Simplexable

While working on a new React.js project (more on this later), I ran into a problem with Cross-Origin-Request errors. I am running the React application on a local server at http://localhost:3000. The user submits an account registration form which needs to be processed, and here's where the problem starts.

In my approach, given the complexities of React, and a much greater familiarity with Ajax handling via Jquery, I elected to fall back to the latter for data processing. I am saying “let React handle the visual interface (DOM) and Jquery handle the backend processing (information methods)”. To make this happen, my doSubmit() logic uses Axios.js to make a POST call to the PHP handler. This is where the car hits the wall.

The PHP handler is running on port 80, because this is a standard HTTP call, albeit with a JSON array as the inbound dataset. I could probably do something with routing in React to get the request delivered to the handler, but that violates the above rule of separation. After some research, I elected to do something more selective than try to get header("Access-Control-Allow-Origin: *"); to work. The main reasons are that (a) this won't work at all on my handler which has no header to set, and (b) I don't want the handler to be wide open. I think it's actually desirable to restrict who can reach the core business logic.

With full credit to this post, I came up with a “whitelisting” technique on the front end of the handler.

<?php
$whitelist = array (
'http://localhost:3000',
'http://clark.local:3000',
'http://clark.local:80'
);
$origin = $_SERVER['HTTP_ORIGIN'];
if (in_array ($origin, $whitelist)) {
header("Access-Control-Allow-Origin: {$origin}");
header('Access-Control-Allow-Credentials: true'); header('Access-Control-Max-Age: 86400'); // cache for 1 day
header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE");
header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}");
}

?>

Problem solved! If the request is not in $whitelist, the request is tossed out as a CORS error. I don't have to risk exposing the logic due to CORS being all-or-none.