CORS in Kirby as external API

Kirby is running under localhost:8000
Frontend is running under localhost:3000

Fetching data from /api
gives the following error:

Access to XMLHttpRequest at ‘http://localhost:8000/api/site’ from origin ‘http://localhost:3000’ has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: It does not have HTTP ok status.

Any Idea how to solve this?

Maybe this helps: Kirby 3 as Headless CMS for Vue/Nuxt

you could try putting

 header("Access-Control-Allow-Origin: http://localhost:3000");

into your index.php.

For pure PHP that would be enough. Don’t know if Kirby does some additional checking on the serverside to prevent cross origin requests…
Also, maybe the Kirby API doesn’t respond to preflight requests (those HTTP requests that use method OPTIONS instead of GET or POST). In that case, having a proxy (like texnixe said) is probably the only option.

Thanks for the answers.
The Allow Origin is set to * or localhost, otherwise the error would be “Does not have set allow origin”. But the error is: “it does not have http ok status”
Which brought me to the point to add my own status reply.
I dont know why I should proxy it instead?
For example this works, in site/config.php:

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
  header("HTTP/1.1 200 OK");
}
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Headers: content-type, authorization, origin, x-requested-with');
header('Access-Control-Allow-Methods', 'GET, OPTIONS');

But I dont know why Kirby is not allowing the OPTIONS method? Isn’t this crucial to the use of APIs in general?

I guess the proxy would essentially do the same you did and respond to the options request.
The preflights matter only for cors requests; I guess most kirby sites, even those who use kirby in headless mode, ultimately serve the frontend app from the same origin as where kirby lives, so the preflight is never done.
It’s not that Kirby disallows OPTIONS requests, it’s simply not responding to them (= status 404) because they don’t match any configured route.
Many routes either restrict to one method or don’t define them at all, and those then fall back to restrict to “only GET”.

I guess it could be a feature to respond to OPTIONS requests.
I have to check if we can do some kind of “catchall” api routes and define a response for options requests. In that case it could be a plugin

don’t know if this is better than what you already have…

config.php

<?php

header('Access-Control-Allow-Origin: http://localhost:3000');

return [
    'api' => [
        'routes' => [
            [
                'pattern' => '(:all)',
                'method' => 'OPTIONS',
                'auth' => false, //or true, depends on what you're doing
                'action' => function() {
                    return true;
                }
            ]
        ]
    ]
];

difference is that this only responds to options requests to api calls, not the whole site…