* // Your inline JavaScript * * * * ``` * * Or using the directive: * ```blade * * ``` * * ## Security * * - Nonces are generated once per request and cached * - Uses cryptographically secure random bytes * - Base64-encoded for safe use in HTML attributes * - Nonces are 128 bits (16 bytes) by default */ class CspNonceService { /** * The generated nonce for this request. */ protected ?string $nonce = null; /** * Whether nonce-based CSP is enabled. */ protected bool $enabled = true; /** * Nonce length in bytes (before base64 encoding). */ protected int $nonceLength = 16; public function __construct() { $this->enabled = (bool) config('headers.csp.nonce_enabled', true); $this->nonceLength = (int) config('headers.csp.nonce_length', 16); } /** * Get the CSP nonce for the current request. * * Generates a new nonce if one hasn't been created yet. */ public function getNonce(): string { if ($this->nonce === null) { $this->nonce = $this->generateNonce(); } return $this->nonce; } /** * Generate a cryptographically secure nonce. * * Also registers it with Vite so Livewire and Vite-generated tags * automatically include the nonce attribute. */ protected function generateNonce(): string { $nonce = base64_encode(random_bytes($this->nonceLength)); Vite::useCspNonce($nonce); return $nonce; } /** * Get the nonce formatted for a CSP directive. * * Returns the nonce in the format: 'nonce-{base64-value}' */ public function getCspNonceDirective(): string { return "'nonce-{$this->getNonce()}'"; } /** * Get the nonce as an HTML attribute. * * Returns: nonce="{base64-value}" */ public function getNonceAttribute(): string { return 'nonce="'.$this->getNonce().'"'; } /** * Check if nonce-based CSP is enabled. */ public function isEnabled(): bool { return $this->enabled; } /** * Enable nonce-based CSP. */ public function enable(): self { $this->enabled = true; return $this; } /** * Disable nonce-based CSP. */ public function disable(): self { $this->enabled = false; return $this; } /** * Reset the nonce (for testing or special cases). * * This should rarely be needed in production. */ public function reset(): self { $this->nonce = null; return $this; } /** * Set a specific nonce (for testing purposes only). */ public function setNonce(string $nonce): self { $this->nonce = $nonce; return $this; } }