hexafuchs / laravel-cookie-consent
Handles storing cookie consent and checking if cookies can be set
Requires
- php: ^8.3
- illuminate/contracts: ^12.24||^11.45
- laravel/framework: ^12.0||^11.0
- laravel/sanctum: ^4.2
- laravel/tinker: ^2.10
- spatie/laravel-package-tools: ^1.92
- swaggest/json-schema: ^0.12.43
Requires (Dev)
- larastan/larastan: ^3.7
- laravel/pint: ^1.24
- mockery/mockery: ^1.6
- nunomaduro/collision: ^8.8.0
- orchestra/testbench: ^10.4.0||^9.0.0
- pestphp/pest: ^4.1
- pestphp/pest-plugin-arch: ^4.0
- pestphp/pest-plugin-laravel: ^4.0
- phpstan/extension-installer: ^1.4
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-phpunit: ^2.0
README
Handles storing cookie consent and checking if cookies can be set
Installation
You can install the package via composer:
composer require hexafuchs/laravel-cookie-consent
You can install all required assets of the library using artisan:
php artisan cookie-consent:install
You can publish the jsonschema with:
php artisan vendor:publish --tag="cookie-consent-schemas"
Usage
To specify which cookies are allowed and which are not, you can use the cookies.json
file.
If you have not used the install command, export it using this command:
php artisan vendor:publish --tag="cookie-consent-specs"
You should now have a cookies.json
file in your resources
directory. It is there on purpose so you can access it
directly from your frontend code to display a proper consent banner. You can change the location in the config.
These properties are officially supported for cookies:
name
(required)description
(required)lifetime
(in hours, required)group
(required)sameSite
(optional)secure
(optional)httpOnly
(optional)path
(optional)domain
(optional)
If you pass required
as group (or whatever you set as cookie-consent.group_names.required
) a cookie will always
be set and never be removed, as it is considered, by definition, to be required. You have to do your own research what
might be considered required and can be set even without consent depending on the relevant jurisdictions.
If you are setting a cookie using the CookieConsentManager
, it will automatically respect the lifetime
and optional
properties and set them correctly. Otherwise, you will need to make sure you input the correct value for the lifetime
,
and all other properties that are shown to the user in your consent banner.
If you wanna set the lifetime as days, set the config value cookie-consent.lifetime_multiplier
to 60 * 24
.
You can add more properties, but if you want to validate them, you need to extend the official jsonschema.
If you are finished, clear the cache to make sure the new schema is loaded. You can also manually purge these cache keys
cookie-consent-specs-schema
and cookie-consent-specs-specs
.
Here are some of the important methods of the CookieConsentManager
:
use Hexafuchs\CookieConsent\Services\CookieConsentManager;
$consentManager = app(CookieConsentManager::class);
$consentManager->storeCookieConsent(['required', 'analytics'], ['someAllowedCookie'], ['someDisallowedCookie']);
$consentManager->resetCookieConsent();
$consentManager->clearIncomingCookies($request);
$consentManager->clearOutgoingCookies($response);
$consentManager->setCookie('someCookie', 'someValue'); // Note that ttl, domain and similar are read from the cookie specs file
$consentManager->canSetCookie('someCookie');
If you wanna apply the consent to all incoming and outgoing requests, you can use the middleware in your bootstrap/app.php
file:
use Hexafuchs\CookieConsent\Middleware\ClearCookieMiddleware;
return Application::configure(basePath: dirname(__DIR__))
->withMiddleware(function (Middleware $middleware): void {
$middleware->web(append: [
ClearCookieMiddleware::class
]);
})->create();
There is also an example implementation of an http controller that handles the consent:
use Hexafuchs\CookieConsent\Controllers\CookieController;
use Hexafuchs\CookieConsent\Middleware\ClearCookieMiddleware;
Route::controller(CookieController::class)
->prefix('cookie')
->name('cookie.')
->withoutMiddleware(ClearCookieMiddleware::class)
->group(function () {
Route::post('/consent', 'consent')->name('consent.store');
Route::delete('/consent', 'clearConsent')->name('consent.clear');
Route::post('/', 'setCookie')->name('cookie.store');
});
Development
Installation
Install the dependencies using composer:
composer install --no-interaction --no-progress
Make sure you have pipx installed and available on your system. Then install the pre-commit hooks:
pipx run pre-commit install
Dev Server
compoer run serve
Testing
composer run test
# Coverage:
composer run test:coverage
If you are requiring artisan-like commands, you can use take a look at testbench:
vendor/bin/testbench list
# e.g. vendor/bin/testbench tinker
Run Tools
composer run lint # runs phpstan
composer run format # runs pint
Installing new dependencies
Install dependencies with composer:
composer require "<dependency>"
# or: composer require "<dependency>" --dev
# or: composer config suggest.<dependency> 'reason'
Create documentation locally
Before first run, you must install phpdoc:
composer run docs:install
# or manually: mkdir -p .bin && wget https://phpdoc.org/phpDocumentor.phar && mv phpDocumentor.phar .bin/phpdoc
composer run docs
You can find the documentation under
docs/build/index.html
Tag a new version
Make sure you commit any pending changes first.
git tag vx.y.z -m "Release Name"
Update pre-commit hooks
pipx run pre-commit autoupdate
pipx run pre-commit install
Building
composer run build
Publish package
There is no need to publish the package manually. Publishing works using webhooks.
License
Copyright (c) 2025 Hexafuchs team@hexafuchs.de
Please see License File for more information.