How to add CSP nonce in inline style and script injected by Vue in a laravel and vue project using Vite
Stefan Bogdanescu
Founder & Senior Architect · 2026-06-29
How to Add CSP Nonce in Inline Styles and Scripts Injected by Vue in a Laravel and Vue Project using Vite
When implementing Content Security Policy (CSP), especially with strict directives like script-src and style-src, developers often encounter issues when trying to use inline styles or scripts. The errors you are seeing—specifically the requirement for 'unsafe-inline' or a nonce—indicate that your CSP is successfully blocking arbitrary inline content, which is a security feature.
As a senior developer working within the Laravel and Vue ecosystem using Vite, the solution lies in correctly synchronizing your server-side nonce generation with your client-side rendering process. This guide will walk you through fixing those EvalErrors and ensuring your dynamic Vue components adhere to your CSP rules.
Understanding the CSP Challenge
Your observation is spot on:
the 'unsafe-inline' keyword, a hash ('sha256-nMxMqdZhkHxz5vAuW/PAoLvECzzsmeAxD/BNwG15HuA='), or a nonce ('nonce-...') is required to enable inline execution.This message means the browser is enforcing the policy defined in your HTTP response headers (which are populated by packages like spatie/laravel-csp). If you inject an inline <script> or <style> tag directly into the DOM via Vue, that content must be explicitly authorized by the CSP.
The core problem often stems from how the nonce is generated on the server and how it's correctly propagated into the HTML output that Vue then manipulates.
The Solution: Synchronizing Server-Side Nonce with Client-Side Injection
To fix this, you need to ensure that every piece of dynamic content generated by your application—whether it’s a style block or a script tag—carries the unique nonce generated during the request lifecycle.
Step 1: Generating and Passing the Nonce in Laravel
Since you are using spatie/laravel-csp, the generation is handled on the server. You must ensure this nonce is available to your Blade view, which subsequently renders the HTML that Vue interacts with.
In a typical Laravel setup, the nonce is usually injected into the <head> section of your main layout file. Ensure your middleware or controller logic correctly fetches the generated CSP nonce and makes it accessible to all views needing inline execution.
Step 2: Binding the Nonce in Your Blade View
Your main layout file (e.g., resources/views/layouts/app.blade.php) must correctly place the CSP nonce attribute on the relevant elements where dynamic content might be injected.
Consider how Vue injects styles or scripts. If you are using standard Vue directives, ensure any dynamically inserted content is wrapped in a way that includes the nonce if it's intended to execute inline.
If you are dynamically injecting custom <style> blocks via a Blade component or direct rendering, structure it like this:
<head>
<!-- This nonce must be generated per request -->
<meta name="csp-nonce" content="{{ $cspNonce ?? '' }}">
{{-- Other CSP directives --}}
</head>
<body>
{{-- Vue application mounts here --}}
<div id="app"></div>
{{-- Example: Injecting dynamic styles that require the nonce --}}
<style nonce="{{ $cspNonce ?? '' }}">
/* Styles injected dynamically by Vue or Blade */
.dynamic-class { color: blue; }
</style>
</body>Step 3: Handling Dynamic Injection in Vue
When Vue injects styles or scripts, if you are using methods like v-bind or dynamic injection into the DOM (e.g., using v-html), you must ensure that any raw HTML strings are correctly validated against the CSP rules.
For dynamically generated scripts, it is generally safer and more compliant with strict CSPs to prefer loading scripts from external files (managed by Vite) rather than injecting complex logic directly as inline code, unless absolutely necessary. If you must use inline styles or scripts for small component-level changes:
- Use Dynamic Binding: Instead of writing raw HTML strings that try to bypass security, bind the content using standard Vue expressions.
- Verify Injection Point: Ensure the injection point is within a context where the nonce is correctly recognized. If you are injecting code into a slot or component output, verify that the parent structure handles the nonce inheritance properly.
For complex scenarios involving dynamic script execution, review how your application initializes assets. Adhering to structured asset loading practices, similar to those promoted by Laravel's approach to asset management (as seen in projects following best practices outlined on laravelcompany.com), helps maintain consistency and security.
Conclusion
The conflict you are experiencing is a classic example of strict CSP interacting with dynamic frontend frameworks. The fix is not about disabling the nonce system but ensuring that every piece of inline content generated by your Laravel backend—which Vue then manipulates—is explicitly signed with the correct nonce. By meticulously managing the flow of the server-generated nonce from Laravel through Blade into the final HTML output, you can successfully satisfy the Content Security Policy and ensure a secure, functional application.