Browsers block cross-origin requests unless the API says otherwise.
This tutorial explains the mechanism, then walks through enabling it in Dotkernel API with mezzio/mezzio-cors: installing the package, registering its ConfigProvider, piping its middleware before routing, and configuring allowed origins, headers, cache duration and credentials in config/autoload/cors.local.php.
Cross-Origin Resource Sharing or CORS is an HTTP header-based mechanism that allows a server to indicate any other origins (domain, scheme, or port) than its own from which a browser should permit loading of resources.
When integrating an API, most developers have encountered the following error message:
Access to fetch at RESOURCE_URL from origin ORIGIN_URL has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.
This happens because the API (RESOURCE_URL) is not configured to accept requests from the client (ORIGIN_URL).
Dotkernel API fixes this issue using the mezzio/mezzio-cors library.
To install mezzio/mezzio-cors, run the following command:
composer require mezzio/mezzio-cors
Register mezzio/mezzio-cors in your application by adding its ConfigProvider to your application's config aggregator.
Open the file config/config.php and paste the below lines at the beginning of the array passed to ConfigAggregator:
Laminas\Diactoros\ConfigProvider::class,
Mezzio\Cors\ConfigProvider::class,
Save and close the file.
Add mezzio/mezzio-cors middleware to your application's pipeline.
Open config/pipeline.php and paste the below line before the one with RouteMiddleware::class:
$app->pipe(\Mezzio\Cors\Middleware\CorsMiddleware::class);
Save and close the file.
Create and open file config/autoload/cors.local.php and add the following code inside it:
<?php
declare(strict_types=1);
use Mezzio\Cors\Configuration\ConfigurationInterface;
return [
ConfigurationInterface::CONFIGURATION_IDENTIFIER => [
'allowed_origins' => [
ConfigurationInterface::ANY_ORIGIN,
],
'allowed_headers' => ['Accept', 'Content-Type', 'Authorization'],
'allowed_max_age' => '600',
'credentials_allowed' => true,
'exposed_headers' => [],
],
];
This list explains the above configuration values:
allowed_origins: an array of domains that are allowed to interact with the API (default ConfigurationInterface::ANY_ORIGIN which means that any domain can make requests to the API)allowed_headers: an array of allowed custom headersallowed_max_age: the maximum duration, since the preflight response may be cached by a clientcredentials_allowed: allows a request to pass cookiesexposed_headers: an array of headers which are being exposed by the endpointSave and close the file.
On the production environment, make sure you allow only specific origins by adding them to the
allowed_originsarray and removing the current value ofConfigurationInterface::ANY_ORIGIN.
For more info, see mezzio/mezzio-cors documentation.
Q: Why do I get a "No 'Access-Control-Allow-Origin' header" error?
A: The API is not configured to accept requests from the calling origin.
Add that origin to allowed_origins.
Q: Where must the CORS middleware sit in the pipeline?
A: Before RouteMiddleware::class, so preflight requests are answered without needing to match a route.
Q: Which origins should production allow?
A: Only the ones that genuinely consume the API.
Replace ConfigurationInterface::ANY_ORIGIN with an explicit list before deploying.
Q: What does credentials_allowed control?
A: Whether the browser may send cookies with cross-origin requests. Enable it only if your clients rely on cookie-based state.
Q: What is allowed_max_age for?
A: It sets how long a client may cache the preflight response, in seconds. A higher value means fewer preflight round trips.
Q: When do I need to change allowed_headers?
A: Whenever clients send a header not already listed — the defaults cover Accept, Content-Type and Authorization.
Q: What is exposed_headers for?
A: It lists response headers the browser should make readable to client-side code; by default only a small set of standard headers is exposed.
Q: Do I need to install the package on a fresh Dotkernel API?
A: No. mezzio/mezzio-cors ships with the project and cors.local.php is created during installation — you only need to review its values.
See Configuration files.