Search code examples
phpajaxcorslocalhostcross-domain

Why is it triggering a CORS error if I'm making a request from backend (PHP)?


I'm being blocked by a CORS exception (Cross-Origin Request Blocked). I know it happens when the front end tries to send a request to an external server domain (in most cases, because they won't contain a Access-Control-Allow-Origin header), however, I'm making it from a PHP script. Why does it happen?

index.html

<!DOCTYPE html>
<html lang="pt-br">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <script src="index.js?"></script>
</head>
<body>
    
</body>
</html>

index.js

json = {
    data: {
    // my data
    }
}

post_data = JSON.stringify(json);

$(document).ready(function() {
    $.ajax({
       type: "POST",
       url: "main.php",
       data: post_data,
       contentType: "application/json"
    }).done(function(response) {
        console.log(response);
    }).fail(function(error) {
        console.log(error);
    });
});

main.php

if (!isset($_SESSION)) {
    session_start();
}
        
if (!isset($_SESSION["ML_ACCESS_TOKEN"])) {
    $_SESSION["REFERER"] = $_SERVER["PHP_SELF"];
        
    header("Location: ".AUTH);
    exit;
} else {
    unset($_SESSION["REFERER"]);
}

if (isset($_POST["data"])) {
    $_POST = json_decode(file_get_contents("php://input"), true);

    $request = new Request;

    $url = // external url
    $headers = // headers
    $data = $_POST["data"];
    $json = json_encode($data);

    $response = $request->post($url, $headers, $json);

    print_r($response);
}

I expected it to make the request and print the response in the index page. I'm using a localhost server, Apache2 and Ubuntu. Is it because I have not directly redirected index to main? When I make a post to main, does the browser actually think index is making the request? If so, how could I make this request? When i execute main.php, it works just fine.

EDIT 1

All files, index.html, as well as main.php are located in a project folder in /var/www/html, hence being the same domain, right?

Entire error message:

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://api.domain.com/authorization?response_type=code&client_id=123. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing). Status code: 302.

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://api.domain.com/authorization?response_type=code&client_id=123. (Reason: CORS request did not succeed). Status code: (null).

EDIT 2

Actually, the request triggering an error is not the one stated in main.php, I'm sorry. This file contains the request I want to make, however the system detects there's not a session token and redirects the user to auth.php to generate it. The first step to generate a token is to redirect the user to api.domain.

auth.php

$auth_url = "https://api.domain.com/authorization";
$auth_data = array(
    "response_type" => "code",
    "client_id" => $this->getClientId()
);

$url = $auth_url."?".http_build_query($auth_data);

header("Location: $url");
exit;

Also, there's the current notice in /var/log/apache2/error.log

[Tue May 09 15:04:04.359422 2023] [php7:notice] [pid 26978] [client 127.0.0.1:60066] PHP Notice:  Undefined variable: _SESSION in /var/www/html/project/request.class.php on line 82, referer: http://localhost/project/index.html

And I've also tested it on Chromium:

Access to XMLHttpRequest at 'https://api.domain.com/authorization?response_type=code&client_id=123' (redirected from 'http://localhost/project/main.php') from origin 'http://localhost' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.

EDIT 3

The basic execution of the program is that index.html imports index.js, which sends a post request to main.php. When the main file checks that there's not an active session, it redirects to auth.php and then it's the one responsible for redirecting the user domain.com to generate a token. It must be a redirect because the user needs to log in their platform and i would redirect back.

I have tested executing each of the mentioned files when there's not an active session and here's what I've got:

  • index (HTML/JS): sends post to main, which redirects to auth, which attempts to redirect to domain.com and fails.
  • main (PHP): redirects to auth, which redirects to domain.com successfully.
  • auth (PHP): redirects to domain.com successfully.

So the problem here is the communication between my frontend and backend. My guess is that the browser somehow interprets that index itself is redirecting to domain.com and hence blocks it through CORS policy.

Main.php is responsible for making post requests to the API i'm using, which receives data from the frontend.

Why would it be the case? Should I not be making the post request in the first place?


Solution

  • As mentioned by Guy Incognito,

    If main.php redirects to auth.php with header() and auth.php redirects to domain.com with header() then that's exactly equivalent (from CORS point of view) of making an Ajax request to domain.com directly from the frontend.

    That said, I managed to find two possible solutions:

    • Redirect index.js to main.php using window.location.href = "./auth.php"; or
    • Rename index.html to index.php and check the session at the start of the page, as follows:
    <?php
    
    if (!isset($_SESSION)) {
        session_start();
    }
    
    if (!isset($_SESSION["ML_ACCESS_TOKEN"])) {
        $_SESSION["REFERER"] = $_SERVER["PHP_SELF"];
    
        header("Location: ".AUTH);
        exit;
    } else {
        unset($_SESSION["REFERER"]);
    }
    
    ?>
    

    Observation: I was using "REFERER" session variable since $_SERVER's "HTTP_REFERER" was not a reliable source since it's not always present.