sfw/fix
419 medium

HTTP 419 Page Expired (Laravel CSRF Token Mismatch)

Laravel returns 419 when a POST request arrives with a missing, stale, or mismatched CSRF token.

What you see

419 | PAGE EXPIRED

This page has expired due to inactivity.
Please refresh and try again.

What’s actually happening

A form that worked a minute ago now bounces back with "Page Expired" on submit. It hits hardest on login screens left open in a tab, and on AJAX/SPA calls that forgot the token. In storage/logs/laravel.log you'll find Illuminate\Session\TokenMismatchException thrown from the VerifyCsrfToken middleware.

Common causes

  • The Blade form is missing @csrf (or the legacy {{ csrf_field() }}), so no _token field is posted.
  • The session expired — config/session.php lifetime elapsed while the form sat open — so the stored token no longer matches.
  • AJAX/fetch requests don't send the X-CSRF-TOKEN header (from the <meta name="csrf-token"> tag) or the X-XSRF-TOKEN cookie.
  • SESSION_DOMAIN / SESSION_SECURE_COOKIE misconfigured behind a proxy or across subdomains, so the session cookie never comes back.
  • Caching the rendered HTML (full-page cache, CDN) serves a token tied to a session the visitor doesn't have.

How to fix it

  1. Put the token in the formAdd @csrf inside every <form method="POST">. Laravel renders a hidden <input name="_token">. For HTML forms that must use PUT/PATCH/DELETE, also add @method('PUT').
  2. Send the header on AJAXEnsure <meta name="csrf-token" content="{{ csrf_token() }}"> is in your layout <head>, then set the header globally: axios.defaults.headers.common['X-CSRF-TOKEN'] = document.querySelector('meta[name=csrf-token]').content. For Sanctum SPAs, hit /sanctum/csrf-cookie first so the XSRF-TOKEN cookie is set.
  3. Extend or refresh the sessionIf users sit on pages a long time, raise 'lifetime' in config/session.php, or refresh the token client-side. For login pages specifically, you can add the route to the $except array in VerifyCsrfToken (acceptable for login since credentials are the real check).
  4. Fix the session cookie behind a proxySet SESSION_DOMAIN to your apex (e.g. .example.com), SESSION_SECURE_COOKIE=true under HTTPS, and confirm TrustProxies is forwarding X-Forwarded-Proto so Laravel knows the request is secure and the cookie actually round-trips.
  5. Don't cache token-bearing pagesExclude any page containing a CSRF token from full-page/CDN caching, or inject the token client-side after load so every visitor gets one matched to their own session.

Stop it recurring

Always pair @csrf in forms with a global X-CSRF-TOKEN header for AJAX, and keep session lifetime longer than your slowest form-fill.

Related errors