Authentication
Lock the headless KQL endpoint and global routes behind a bearer token, or fall back to Kirby's native API authentication.
Bearer Token Authentication
Protect the Kirby Headless /api/kql endpoint with a bearer token by setting kql.auth to 'bearer' and defining a secret token in your config.php:
site/config/config.php
return [
'kql' => [
// Enable bearer token authentication for KQL
'auth' => 'bearer'
],
'headless' => [
'token' => 'your-secret-token'
]
];
Include the token in your requests using the Authorization header:
const response = await fetch("https://example.com/api/kql", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.KIRBY_API_TOKEN}`,
},
});
Store your token securely and never commit it to version control. Use environment variables in production.
What the Token Protects
With global routes enabled, every page is served as JSON through a single catch-all route. That route matches every HTTP method and validates the bearer token before it resolves anything:
site/config/config.php
return [
'headless' => [
'globalRoutes' => true,
'token' => 'your-secret-token'
]
];
- Page JSON requires the token.
- Clean file URLs such as
/about/hero.jpgrequire the token. They are additionally opt-in through Kirby'scontent.fileRedirectsoption, which is disabled by default – without it, files are only reachable through their media URL. - Media URLs such as
/media/pages/about/hero.jpgnever require the token, so images returned by$file->url()keep working in a browser that cannot send anAuthorizationheader. - The
/api/__sitemap__and/api/__template__endpoints require the token as well. They are not part of the catch-all and stay available even withglobalRoutesdisabled – which also means they are public whenever no token is set.
Leaving
headless.token unset disables authentication entirely and serves the whole site publicly – a supported setup for public sites, but rarely what you want otherwise. A token that is set but blank – empty or whitespace only, the common result of an unresolved environment variable – rejects every request with 401 instead.KQL Endpoint Authentication
kql.auth decides who may query the /api/kql endpoint. Every value keeps caching and multi-language support:
true(default) – Kirby's native API authentication: a Panel session, or HTTP Basic auth whenapi.basicAuthis enabled'bearer'– theheadless.token; without a token, it falls back totruefalse– public, for an endpoint you open on purpose
For HTTP Basic auth, enable it in Kirby's API options:
site/config/config.php
return [
// Enable HTTP Basic authentication for the Kirby API
'api' => [
'basicAuth' => true
],
// Use Kirby's native API authentication for KQL (default)
'kql' => [
'auth' => true
]
];
The official KQL plugin's own
/api/query endpoint is untouched – Kirby Headless registers /api/kql only.