Fixing Laravel 12 + Livewire 419 "Page Expired" in an iframe (without disabling CSRF)

Solving Laravel 12 + Livewire 419 "Page Expired" in an iframe

After upgrading one of our projects to Laravel 12 with Livewire, I encountered a frustrating issue: every Livewire request inside an iframe returned 419 Page Expired.

The architecture looks like this:

Website (Laravel)
        │
        │ iframe
        ▼
UUI (Laravel + Livewire)
https://uui-v5.local/forms/...

The public website embeds the UUI application, where users can complete and submit forms.

The symptom

The form loaded successfully, but as soon as the user interacted with it, Livewire sent a request to:

POST /livewire/update

Laravel responded with:

419 Page Expired

At first, I temporarily "fixed" it by excluding Livewire from CSRF validation:

$middleware->validateCsrfTokens(except: [
    'livewire/*',
]);

Although this worked, it wasn't the correct solution because it disabled CSRF protection for every Livewire request.

The real problem

The issue wasn't Livewire.

It wasn't Laravel.

It wasn't even CSRF.

The real problem was that the browser wasn't sending the session cookie.

While debugging, I noticed Chrome showed:

Not Secure
https://uui-v5.local

Since my local HTTPS certificate wasn't trusted, the browser didn't consistently treat the connection as secure. As a result:

  • the session cookie wasn't available inside the iframe,

  • Laravel couldn't restore the user's session,

  • the CSRF token couldn't be validated,

  • every Livewire request failed with a 419 response.

The fix

After configuring HTTPS correctly for my local environment and trusting the certificate, I updated the session configuration:

APP_URL=https://uui-v5.local

SESSION_DOMAIN=null
SESSION_SECURE_COOKIE=true
SESSION_SAME_SITE=none

Because the application is embedded in an iframe on another origin, SESSION_SAME_SITE=none and SESSION_SECURE_COOKIE=true are required.

After clearing the configuration cache:

php artisan optimize:clear

the browser began sending the laravel_session and XSRF-TOKEN cookies correctly.

Livewire started working immediately.

CSRF configuration

Once the session issue was fixed, I removed the unnecessary CSRF exclusions:

$middleware->validateCsrfTokens(except: [
    'stripe/webhook',
]);

I no longer needed:

'livewire/*',
'form/*',

Key takeaway

A public form does not mean you should disable CSRF protection.

Laravel can generate a session and CSRF token for anonymous users just as it does for authenticated users.

Only endpoints that receive requests from external systems—such as Stripe webhooks, GitHub webhooks, or other third-party callbacks—should typically be excluded from CSRF validation.

Debugging checklist

If you encounter a 419 Page Expired error with Livewire, check the following before disabling CSRF:

  • Is the application using HTTPS?

  • Is the HTTPS certificate trusted?

  • Does POST /livewire/update include the laravel_session cookie?

  • Does the request include the XSRF-TOKEN cookie?

  • Are SESSION_SECURE_COOKIE and SESSION_SAME_SITE configured correctly?

  • If using an iframe, are third-party cookies being blocked by the browser?

Final thoughts

If excluding livewire/* "fixes" a 419 error, there's a good chance the real issue is your session or cookie configuration, not Livewire itself.

Fix the underlying session problem first, and you can keep Laravel's built-in CSRF protection fully enabled—exactly as intended.

Comments