search

Home  >  Q&A  >  body text

CORS issue in PHP: Response from preflight request not passing. allowed sources

So I know there are a lot of CORS posts out there and I'm just adding them but I can't find any answers that can help me. So I'm building an Angular 4 application that relies on my php api. It works fine locally, when I throw it on the domain with the app at app.example.com and the api at api.example.com I can't Because of my login I get the following error:

XMLHttpRequest cannot load http://api.example.com/Account/Login. Response to preflight request failed access control check: No 'Access-Control-Allow-Origin' header present in request resource. So source "http://app.example.com" is not allowed access.

My php code looks like this:

$http_origin = $_SERVER['HTTP_ORIGIN'];

$allowed_domains = array(
    'http://example.com',
    'https://example.com',
    'http://app.example.com',
    'https://app.example.com',
    'http://www.example.com',
    'https://www.example.com'
);

if (in_array(strtolower($http_origin), $allowed_domains))
{  
    // header("Access-Control-Allow-Origin: *");
    header("Access-Control-Allow-Origin: $http_origin");
    header('Access-Control-Allow-Credentials: true');
    header('Access-Control-Max-Age: 86400');
}

// Access-Control headers are received during OPTIONS requests
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
        header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
        header("Access-Control-Allow-Headers: Authorization, Content-Type,Accept, Origin");
    exit(0);
}

My Angular post looks like this:

public login(login: Login): Observable<LoginResponse> {
    let headers = new Headers();
    headers.append('Content-Type', 'application/x-www-form-urlencoded');
    headers.append('Authorization', 'Basic ' + btoa(login.Username + ':' + login.Password));
    return  this.http.post(this.apiBaseUrl + '/Account/Login', "grant_type=client_credentials", { headers: headers })
        .map(response => {
            // code
        });
}

If I run the request through Postman (this does not affect CORS) I get:

{ "error": "invalid_client", "error_description": "Client credentials were not found in the headers or body" }

I tried setting the origin to '*' just to test and see if this was the core of the problem, but it still failed the same way.

edit Just updating with the information below. Changing the case in the header has no effect, and pulling the code out of the if statement has no effect either.

I debugged the php by telling my live application to go to the local api and the php is working as expected. It sets the header and puts it into every if statement.

Edit Shot 2 I really need some help and if anyone has any ideas I would really appreciate it.

Edit Shot 3 If I set all the header stuff in .htaccess instead of php it lets me pass. However, now I'm stuck with the error listed above, which is the error I always get when using Postman, but now when using the actual website.

{"error":"invalid_client","error_description":"Client credentials not found in header or body"}

My response headers are like this

Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:authorization, content-type, accept, origin
Access-Control-Allow-Methods:GET, POST, OPTIONS
Access-Control-Allow-Origin:*

Once it's working I'll change it from * to just my domain. But now I leave it as *.

As requested my header.

P粉564192131P粉564192131420 days ago696

reply all(2)I'll reply

  • P粉952365143

    P粉9523651432023-10-22 00:47:32

    In my similar case, Angular frontend and Php backend helped with the code below. First I send a header:

    header("Access-Control-Allow-Origin: http://localhost:4200");   
    header("Content-Type: application/json; charset=UTF-8");    
    header("Access-Control-Allow-Methods: POST, DELETE, OPTIONS");    
    header("Access-Control-Max-Age: 3600");    
    header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");

    After them I can ignore option requests:

    if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {    
       return 0;    
    }

    This approach helped me handle "post" and "delete" embedded request methods in Angular.

    reply
    0
  • P粉860370921

    P粉8603709212023-10-22 00:29:25

    Well, I had a similar problem recently and I solved it all on the backend only, without the .htaccess stuff.

    When the browser sends a cross-server request, it first sends an OPTIONS request to ensure that it is valid and that a "real" request can be sent. The "real" request is sent when it gets a correct and valid response from OPTIONS.

    Now, for both requests to the backend, you need to make sure the correct headers are returned: content-type, allow-origin, allow-headers, etc...

    Ensure that in the OPTIONS request on the backend, the application returns the header and returns the response instead of continuing the full flow of the application.

    In a "real" request you should return the correct headers and regular response body.

    Example:

    //The Response object
        $res = $app->response;
    
        $res->headers->set('Content-Type', 'application/json');
        $res->headers->set('Access-Control-Allow-Origin', 'http://example.com');
        $res->headers->set('Access-Control-Allow-Credentials', 'true');
        $res->headers->set('Access-Control-Max-Age', '60');
        $res->headers->set('Access-Control-Allow-Headers', 'AccountKey,x-requested-with, Content-Type, origin, authorization, accept, client-security-token, host, date, cookie, cookie2');
        $res->headers->set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
    
        if ( ! $req->isOptions()) {
            // this continues the normal flow of the app, and will return the proper body
            $this->next->call();
        } else {
            //stops the app, and sends the response
            return $res;
        }

    Things to remember:

    • If you use: "Access-Control-Allow-Credentials" = true Make sure "Access-Control-Allow-Origin" is not "*", it must be set to the correct domain! (A lot of blood was shed here :/)

    • Define the allow headers you will get in "Access-Control-Allow-Headers" If you don't define them, the request will fail

    • If you use "Authorization: Bearer", then "Access-Control-Allow-Headers" should also contain "Authorization", otherwise the request will fail

    reply
    0
  • Cancelreply