CORS & Access-Control-Allow-Origin must not be wildcard

I am looking all over the internet, I’ve watched about 10 hours of API content, and in the examples I am able to follow along no problem, but when it comes to using an API with credentials I’m having loads of issues, simply just cannot get it to work

Everyone on the internet is saying “without knowing what backend you are using, it’s hard to answer”, now I’m not a backend dev, I do not really know what is going on, but I can get kirby to do as I ask with 99% of things, now with this finance company that insist I “POST” all of my vehicles to their API I cannot get this to work at all.

error I’m gettin: Access to fetch at ‘url’ from origin ‘http://localhost’ has been blocked by CORS policy: The value of the ‘Access-Control-Allow-Origin’ header in the response must not be the wildcard ‘*’ when the request’s credentials mode is ‘include’.

I am totally out of my depth, and am actually willing to hire someone to just integrate these things for me at this point if I have to.

Could you please post the code for the request you are making?

var carDetails = { 
    "Credentials": {
        "Username": "USER",
        "Password": "PASS"
      "Vehicles": [
          "Physical": {
            "ExternalVehicleID": "12345",
            "OnTheRoadPrice": "13995",
            "Status": "PreOwned",
            "Type": "Car",
            "VIN": "",
            "IsNew": false,
            "Registration": {
              "RegistrationNumber": "123",
              "DateRegisteredWithDvla": "11/09/2015"
            "Mileage": 34000,
            "Images": [
                "Url": ""
            "DetailedVehicleLink": "",
            "Codes": [
                "Type": "Vrm",
                "Value": "123"
      "Action": "AddOrUpdate"

fetch('API-URL', { credentials: 'include' }, { 
    method: 'POST', 
    body: JSON.stringify(carDetails),
    headers: {
        'Content-Type': 'application/json',
.then(response => response.json())
.then(data => {
  console.log('Success:', data);
.catch((error) => {
  console.error('Error:', error);

taken out the actual user pass and api url,

If I remove the access-control-allow-origin: * header and “{ credentials: ‘include’ },” I get a 401 (unauthorized) instead, and it seems to chuck back success followed by data about the error (nothing in there that seems useful though).

Again apologies for my lack of knowledge and I understand this forum is not meant for this as it’s not exactly kirby related at this point :see_no_evil:

I see some confusion about CORS here. Normally you don’t send access-control-allow-origin with the request. Normally it’s a header you (actually it’s more of interest to the browser than to you) receive in the response (to both a “preflight” OPTIONS request and, if that permits the origin, also the actual POST request).

You probably don’t want to do that API request from the frontend. Also because it contains credentials that probably shouldn’t be public.
In the backend there’s no such thing as an “origin”, so you don’t have CORS problems :slight_smile:.

And since you now have to make that request from your backend, it has become a Kirby related question :sunglasses:

1 Like

You probably want to use the Remote utility class: Remote::request() | Kirby CMS

I don’t have much experience with it, but I’m sure texnixe does :slight_smile:

Definitely more than with JavaScript :wink:

Do you have any examples on how to do this? there’s not a lot in the documentation of kirby about this remote feature, and I feel like I should know more about PHP to understand what is going on! I have no backend experience. I’m getting by with kirby by following the guides!

There’s no documentation about a POST request in particular, but I already posted this example in the other thread:

Here is another example wrapped in a class method for sending data to Campaign Monitor:

	public static function registerSubscriber( $data ) {
		// send data to Campaign-Monitor and wait for response
		$listId   = option('cm.listIdMarketing');
		$endPoint = 'subscribers/' . $listId . '.json';
		$postData = [
			'EmailAddress'   => trim($data['email']),
			'Name'           => strip_tags(trim($data['name'])),
			'ConsentToTrack' => 'No',
		$options = [
			'headers' => [
				'Authorization: Basic ' . base64_encode(option('cm.apikey') . ':')
			'method'  => 'POST',
			'data'    => json_encode($postData),

		return Remote::request(option('cm.baseURL') . $endPoint, $options);