CORS headers working for GET but not for POST



I’ve used the following snippet suggested in the User Guide to enable CORS headers on all responses:

$app->options('/{routes:.+}', function ($request, $response, $args) {
    return $response;

$app->add(function ($req, $res, $next) {
    $response = $next($req, $res);
    return $response
            ->withHeader('Access-Control-Allow-Origin', 'http://localhost')
            ->withHeader('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Accept, Origin, Authorization')
            ->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');

This works fine when sending GET requests from my frontend (in AngularJS) but as soon as I try a POST request, I get the following error in the browser console:

XMLHttpRequest cannot load http://localhost:8888/accounts. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access.

When checking in the Network tab of the browser dev console, I see that CORS headers are sent along the response to the OPTIONS request but not for the response of the POST request that follows.

I even tried to add the headers directly on the response of the actual route but no luck:

$app->post('/account/new', function (Request $request, Response $response) {
	$data = $request->getParsedBody();
	$account_data = [];
	$account_data['name'] = filter_var($data['name'], FILTER_SANITIZE_STRING);
    $account_data['market_id'] = filter_var($data['market_id'], FILTER_SANITIZE_NUMBER_INT);
    $account_data['category_id'] = filter_var($data['category_id'], FILTER_SANITIZE_NUMBER_INT);
    $account_data['flag'] = 'TEST_RESPONSE';
    return $response
            ->withHeader('Access-Control-Allow-Origin', 'http://localhost')
            ->withHeader('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Accept, Origin, Authorization')
            ->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')

I’m sure I’m missing something silly, thanks for any help!


Did you managed to fix this? Have the same problem…


Unfortunately I didn’t solve it. I circumvented the problem by operating the frontend and backend on the same domain.
I’d be glad to get an answer on that especially since I think I stuck close to what the snippet suggests on the help page.
Good luck!



Have you tried replacing the Access-Control-Allow-Origin header with either http://localhost:8888 or *? E.g.:

->withHeader('Access-Control-Allow-Origin', '*')

Note that the origin (in your case the URL of your Angular JS page) must match the Access-Control-Allow-Origin header in scheme (http/https), domain and port number. For CORS “http://localhost” is not the same as “http://localhost:8888”.

Also, check if the headers are actually being sent to the browser. They should be through the middleware (no need to add them to other routes), but the error message you get seems to indicate otherwise:

No ‘Access-Control-Allow-Origin’ header is present on the requested resource.


Indeed, fair point, I tried opening the gates by setting Access-Control-Allow-Origin header to ‘*’ (just to be sure) but it didn’t solve the problem because, as I said in my original post, the problem is actually that no CORS headers are sent in the response of the POST request.
The CORS headers are sent with the response to the OPTIONS request though.
Thanks again for any help toward the resolution.



Thanks for checking.

It is strange that you are not getting the CORS headers from the POST request. I have created a small test, posted below, and I can’t reproduce the missing headers.

Is there perhaps some middleware in your application added before the CORS middleware that is removing the headers that are set by the CORS middleware?

Testing CORS with POST requests
I have set up two PHP built-in webservers. On runs on localhost:8000, the other at localhost:8001. Both running in a separate directory:


<!-- index.html -->
        <script src=""></script>
        <p>Open this page at localhost:8000.</p>
        <div id="response"></div>
            $(function() {
                $.ajax('http://localhost:8001/account/new', { method: "POST", data: { name: 'test123'} })
                .done(function(data) { $('#response').text(JSON.stringify(data)); })
                .fail(function(xhr, textStatus) { $('#response').text('Error: ' + textStatus); });



// index.php

use Slim\Http\Request;
use Slim\Http\Response;
use Slim\App;

require_once __DIR__ . '/vendor/autoload.php';

$app = new App();

$app->options('/{routes:.+}', function ($request, $response, $args) {
    return $response;

$app->add(function ($req, $res, $next) {
    $response = $next($req, $res);
    return $response
            ->withHeader('Access-Control-Allow-Origin', 'http://localhost:8000')
            ->withHeader('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Accept, Origin, Authorization')
            ->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');

// POST call
$app->post('/account/new', function (Request $request, Response $response) {
	$data = $request->getParsedBody();

    $responseData = [
        'name' => $data['name'],
        'flag' => 'TEST_RESPONSE'

    return $response->withJson($responseData);


And the result when I open http://localhost:8000:



I’m just reading your reply, thanks for that!
Indeed, I might be doing something wrong with a middleware that could be stripping headers somewhere (I’m still a learning the framework). Actually, I’m also having a hard time implementing a middleware to manage the authentication process.

I’ll try to find some time to setup a similar test with just the basics and I’ll report once done.

Thanks again for your help.



I’ve experienced the same, yet I confirm that numerous other POST request were working well before this specific one, so I quickly ruled out the http method being the cause itself.

I haven’t found the root cause, but I know I’ve had error in object creation procedure, that resulted in rendering an empty 200 response in the middle of controller method processing the request, rather than throwing an exception. Didn’t have the time to investigate, but I think it was about calling eloquent’s (many-to-many relation) sync() method on an entity that has not been saved yet.

Of course, the problem disappeared when I’ve fixed the error, but I still suspect a bug in the framework.