scify/laravel-cookie-guard
Laravel Cookie Guard is a configurable cookie consent package for Laravel. It adds a GDPR-friendly banner, lets visitors accept or reject cookie categories, remembers their choices, and helps load scripts conditionally through simple Blade helpers and middleware.
php artisan vendor:publish --tag="cookies-consent-config"
php artisan vendor:publish --tag="cookies-consent-public"
php artisan vendor:publish --tag="cookies-consent-translations"
config/cookies_consent.php) — it holds the category list, each category's named cookies, the required list, cookie_prefix, cookie_lifetime, and use_separate_page. Everything the banner renders is driven from here.</body>, so it renders on every page that can set cookies:
<x-cookies-consent::banner />
name key — the package walks the host and its parent domains down to the registrable domain on rejection.use_separate_page and render the separate-page component; in v5.1 both banner variants render the category list onto the root element, so "Accept all" and "Reject optional" now behave correctly there.Banner vs. separate page. Pick one per app: the inline banner for the common case, use_separate_page when legal wants a dedicated consent wall. Both are Blade components with the same contract, so your tests can assert on the same root attributes.
Opening the banner on demand. Link to #consent-settings from your footer ("Cookie settings") — in 5.1 a hash change after load opens the banner rather than toggling it, and a[href="#consent-settings"] links do the same. That means a sitewide footer link is now a safe, idempotent way to let users revisit consent.
SPA stacks (Inertia, Livewire, Turbo). You no longer need to do anything: the save request sends the XSRF-TOKEN cookie as X-XSRF-TOKEN, so the token stays valid on pages that never do a full reload. If you were patching the JS to refresh a stale token, drop that patch.
Posting to the save route yourself. POST /guard-settings/save now runs in the web middleware group with CSRF enforcement. Any custom form or fetch call must send a token — X-XSRF-TOKEN, X-CSRF-TOKEN, or the _token field. Payload shape is one boolean per configured category plus locale; unknown keys are discarded, so sending extra metadata is harmless but pointless.
Custom markup. If you've replaced the package view, keep the root attributes the JS reads: data-cookie-lifetime, data-cookie-categories, data-required-categories, and data-csrf-token (fallback chain is root attribute → csrf-token meta tag).
Translations. Publish into lang/vendor/cookies_consent/{locale}/messages.php and keep only the keys you changed — Laravel merges vendor translations key by key, so untouched strings keep receiving upstream fixes. Swedish is sv; the se directory is gone.
Consent lifetime. cookie_lifetime is what the browser actually stores (it used to be a hardcoded 30 days that disagreed with both the config and the banner copy). Set 0 for a session-scoped consent cookie — good for shared/kiosk machines.
Testing. Pest covers config-driven Blade output and view overrides; the JS bundle is tested with node:test. Mirror that: assert root data attributes in a feature test, and assert cookie erasure on rejection by hitting your own routes after a consent POST.
--tag="cookies-consent-public" --force for the JS, and re-publish the Blade views (or hand-add the four data-* attributes). With pre-5.1 markup the JS silently falls back to 365 days and erases nothing on rejection — a failure with no error./guard-settings/save, it was previously unauthenticated by accident. Add the token. On Laravel 13 same-origin requests without a token are still accepted, which can mask the bug in dev and surface it behind a proxy.$request->boolean() on your side) or send proper JSON booleans.enabled is gone. Remove it from your published config; it never did anything, but leaving it invites someone to "turn the banner off" and be confused.storage/logs/laravel.log after upgrading; if you see the warning, you still have strings in lang/vendor/scify/laravel-cookie-guard/.se must switch to sv or fall back to another locale's strings.strictly_necessary optional — put genuinely optional cookies in a separate category.{cookie_prefix}cookies_consent_selection (which never reached a browser anyway) and the pre-v3 cookieConsent cleanup. If any of your code reads the former, it was always empty — delete the branch. If you still have users with the ancient cookieConsent cookie, expire it yourself.#consent-settings, it no longer closes it.SameSite=Lax + Secure on HTTPS is now set on the consent cookie. If you front the site with a TLS-terminating proxy, make sure TrustProxies is configured or Secure may be omitted on requests Laravel thinks are HTTP.How can I help you explore Laravel packages today?