asignua/filament-csp-nonce
CSP nonce support for Filament: generates a per-request nonce and applies it to Filament's inline scripts and styles, so your admin panel runs under a strict Content Security Policy without unsafe-inline. Simple Laravel/Filament integration with minimal configuration.
This is a patch release (v1.0.1) on top of a 1.0 line — no breaking changes, no new public API. Everything below is the day-to-day shape of working with the package; the fixes mainly change defaults you can now trust.
vendor:publish) before touching any policy. The config is where the report body cap, the error-page rewriting toggle, and the report-uri / report-to wiring live.web group, then hit any page and inspect the Content-Security-Policy (and Reporting-Endpoints, if enabled) response headers with curl -I or the devtools Network tab. Header present and a nonce in it is your "it works" signal.<script> / <style> tags (and your Vite entry tags), then flip the policy to report-only and watch the browser console for a session before enforcing. The package's whole value proposition is that the nonce and the violation reports line up, so verify both ends early.<img src="https://example.com/x.png">) and confirm a row lands wherever the package records reports. As of this release, a full 20-entry Reporting API batch from a real browser is recorded instead of being silently dropped, so this smoke test now actually tells you something.Rollout workflow. Ship report-only first with reporting enabled, collect for a few days, then enforce. Keep the policy definition in one place (config or a policy class) so the report-only/enforce switch is a single flag rather than two divergent directive sets.
Nonce propagation. Generate one nonce per request and thread it through your layout, any Blade components that emit inline scripts, and your asset tags. The v1.0.1 fix matters here: a Blade echo sitting inside another attribute — src="{{ asset('nonce.js') }}" — no longer trips the "a nonce already exists" heuristic. If you previously worked around that by moving asset tags around or disabling the auto-injection, you can remove the workaround.
Report consumption. Point report-to at the package's endpoint and let it own the Reporting-Endpoints header. If you already define a report-to group yourself, the package now leaves it alone instead of clobbering it — so you can keep an app-specific group alongside the package's. Setting report-uri or report-to to null in config genuinely removes the directive now; useful when you want reporting only in staging.
Error pages. Rewriting of framework error views and resources/views/errors is on by default, which means your 403/404/419/500 pages keep their inline styles under the nonce policy without you doing anything. If you maintain custom error views, treat them as CSP surfaces like any other page: inline <style> and <script> need the nonce, and inline event handlers (onclick=) still won't work.
Filament panels. Publish the package's Filament view overrides and register the path in blade.paths, otherwise your overrides are never picked up and you'll debug a policy that isn't actually the one being served. When you use Filament's ->font(), you're loading Bunny Fonts — that requires the relevant fonts.bunny.net origins in font-src (and usually style-src), or the panel renders with fallback fonts and a console full of violations.
Subdirectory installs. report-uri and Reporting-Endpoints now include the app's base path. If the app lives under /admin or similar, verify the reported URL resolves to the actual endpoint rather than the domain root — a mismatch shows up as browsers failing to deliver reports with no server-side error to grep for.
Testing. Assert the header and nonce in feature tests, and post a sample Reporting API payload directly at the intake endpoint to cover the storage path. That route is plain HTTP, so it's cheap to test and it's the piece most likely to break silently.
src="{{ asset(...) }}" false positive is fixed, but the general lesson stands: don't hand-write nonce="..." attributes in templates. Use the provided helper so the value is the real per-request nonce, and so the "already has a nonce" check stays accurate.null vs. unset are different. null removes the directive; leaving the key out falls back to the package default (which is to emit it). If reports aren't arriving, check you removed rather than merely didn't configure.report-to groups win. The package no longer overwrites a group you defined. That's the desired behavior, but it also means a misconfigured custom group will persist through upgrades and quietly take precedence — inspect the emitted header, not just the config.How can I help you explore Laravel packages today?