CORS

Set up cross-origin access for public APIs or authenticated frontends with support for multiple origins and dynamic closures.

Kirby Native CORS Support

Starting with Kirby 5.2.0, CORS is built into Kirby core. Configure it directly in your config.php:

Minimal Setup (Public API)

Enable CORS with sensible defaults:

config.php
return [
    'cors' => true
];

This applies defaults that work for most public APIs: wildcard origin (*), standard HTTP methods, and no credentials.

Headless CMS With Authentication

For headless setups with bearer token authentication:

config.php
return [
    'cors' => [
        'allowOrigin' => 'https://example.com',
        'allowMethods' => ['GET', 'POST', 'PATCH', 'DELETE'],
        'allowHeaders' => true,
        'allowCredentials' => true
    ]
];
Setting allowCredentials to true lets browsers include cookies and HTTP authentication with cross-origin requests. Only enable this when the requesting origin is fully trusted and under your control.

Multiple Frontend Apps

Allow multiple origins with specific configuration:

config.php
return [
    'cors' => [
        'allowOrigin' => [
            'https://app.example.com',
            'https://admin.example.com'
        ],
        'allowHeaders' => [
            'Authorization',
            'Content-Type',
            'X-Language',
            'X-Cacheable'
        ],
        'allowCredentials' => true
    ]
];

Dynamic CORS Configuration

For request-based CORS configuration, use a closure:

config.php
return [
    'cors' => function ($kirby) {
        $origin = $kirby->request()->header('Origin');

        // Allow specific origins with credentials
        if (in_array($origin, ['https://app1.com', 'https://app2.com'])) {
            return [
                'allowOrigin' => $origin,
                'allowCredentials' => true,
                'allowMethods' => ['GET', 'POST']
            ];
        }

        // Fallback to wildcard for other origins
        return ['allowOrigin' => '*'];
    }
];

Available Options

OptionTypeDefaultDescription
allowOriginstring|array'*'Allowed origins (e.g., '*', 'https://example.com', or array for multiple origins)
allowMethodsstring|array['GET', 'HEAD', 'PUT', 'POST', 'DELETE', 'PATCH']Allowed HTTP methods
allowHeadersstring|array|bool[]Allowed request headers. true reflects client headers; array allowlists specific headers
maxAgeintnullPreflight cache duration in seconds
allowCredentialsboolfalseAllow requests with credentials (cookies, auth)
exposeHeadersstring|array[]Response headers exposed to the browser

Security Considerations

Every origin you allow can read your API from a visitor's browser – keep origins, methods, and headers down to what your frontend needs, and reach for the wildcard only on an API that is public anyway.