Skip to main content
A Content Security Policy (CSP) is an HTTP header that helps prevent cross-site scripting (XSS) attacks by restricting which scripts can run on your pages. Ziggy provides multiple ways to work with CSP configurations.

The CSP Challenge

By default, the @routes Blade directive outputs an inline <script> tag:
If your Content Security Policy blocks inline scripts (using script-src 'self'), this script will be blocked and your routes won’t be available.

Solution 1: Using Nonces

The most common solution is to use a nonce (number used once) to whitelist specific inline scripts.

Generating a Nonce

First, generate a cryptographically secure nonce for each request. You can do this in middleware:
app/Http/Middleware/AddCspNonce.php
Register the middleware:
app/Http/Kernel.php

Using the Nonce with @routes

Pass the nonce to the @routes directive:
This generates:
The nonce attribute tells the browser that this specific inline script is safe to execute.

Using Named Parameters

You can combine the nonce with other parameters:

Solution 2: JSON Mode

Alternatively, you can configure Ziggy to output routes as JSON data instead of executable JavaScript:
This outputs:
Scripts with type="application/json" are treated as data by the browser and are not executed, so they’re not blocked by CSP.

Loading the route() Function Separately

When using json: true, the route() function is not included in the output. You must load it separately.
Install Ziggy’s NPM package:
Import the route() function in your JavaScript:
app.js
The route() function will automatically read the Ziggy config from the JSON script tag.

Serving route() from Your Domain

If you don’t want to use NPM, you can serve Ziggy’s JavaScript file from your own domain:
Then include it in your layout:
Since the script is served from your domain and loaded via <script src>, it complies with script-src 'self'.

Solution 3: Using ziggy:generate

For the best CSP compatibility, generate Ziggy’s config as a separate JavaScript file:
Import it in your application:
app.js
Include your bundled JavaScript normally:
This approach:
  • ✅ Works with strict CSP (script-src 'self')
  • ✅ No nonces required
  • ✅ No inline scripts
  • ✅ Can be cached by the browser
  • ✅ Works with JavaScript build tools

CSP Configuration Examples

Strict CSP with Nonces

Use with:

Strict CSP with JSON Mode

Use with:

Strict CSP with ziggy:generate

Use with:
And import in your bundled JavaScript.

Helper Function for Nonces

Create a global helper for accessing the CSP nonce:
app/helpers.php
Use it in your Blade templates:

Laravel Packages for CSP

Several Laravel packages can help manage Content Security Policy:

Spatie’s Laravel CSP

spatie/laravel-csp provides a fluent API for managing CSP headers:
config/csp.php
Access the nonce in Blade:

Bepsvpt’s Secure Headers

bepsvpt/secure-headers provides comprehensive security headers including CSP:

Testing CSP Configuration

Test your CSP configuration by checking the browser console for errors:
If you see this error, your CSP is blocking Ziggy’s inline script. Use one of the solutions above.

CSP in Development

During development, you might want to use a more permissive CSP:
Never use 'unsafe-inline' or 'unsafe-eval' in production. These directives defeat the purpose of CSP and expose your users to XSS attacks.

Choosing the Right Approach

Nonces

Best for: Traditional Laravel apps with server-rendered Blade templatesPros:
  • Simple to implement
  • No build tools required
  • Works with all CSP configurations
Cons:
  • Requires middleware
  • Nonce must be regenerated per request
  • Can’t cache pages with nonces

JSON Mode

Best for: Apps that want inline config but need strict CSPPros:
  • No nonces required
  • Config can be cached
  • Works with strict CSP
Cons:
  • Requires loading route() separately
  • Still has inline content (as JSON)
  • Requires NPM or manual script hosting

ziggy:generate

Best for: SPAs and apps using JavaScript build toolsPros:
  • Strictest CSP support
  • Fully cacheable
  • No inline content
  • Works great with build tools
Cons:
  • Requires regenerating on route changes
  • More complex setup
  • Requires build tools
You can pass a nonce to @routes when using JSON mode:
However, since JSON script tags (type="application/json") are not executed, the nonce is not necessary and will be ignored by browsers. JSON mode is inherently CSP-safe without nonces.
Instead of nonces, CSP supports hash-based whitelisting where you specify the hash of allowed inline scripts:
This is problematic with Ziggy because:
  1. The Ziggy output changes when routes change
  2. The hash would need to be recalculated on every deployment
  3. You’d need to generate and store the hash somewhere
Recommendation: Use nonces instead of hashes for dynamic content like Ziggy’s output.
If you use @routes multiple times on the same page, each call generates a separate <script> tag. You need to use the same nonce for all of them:
Each script tag will include the nonce attribute and be allowed by your CSP policy.

Next Steps

Blade Directive

Learn more about @routes directive options

Generating Config

Use ziggy:generate for the strictest CSP support