laravel/framework · warning · TokenMismatchException

CSRF token mismatch.

Error message

CSRF token mismatch.

What it means

PreventRequestForgery (the successor to VerifyCsrfToken) throws TokenMismatchException when none of its acceptance guards pass: running unit tests, the URI being in the except list, a valid Origin/Sec-Fetch-Site header, or a matching CSRF token. The exception renders as HTTP 419 by default. It exists to stop cross-site request forgery on state-changing verbs.

Source

Thrown at src/Illuminate/Foundation/Http/Middleware/PreventRequestForgery.php:111

     * @throws \Illuminate\Http\Exceptions\OriginMismatchException
     */
    public function handle($request, Closure $next)
    {
        if (
            $this->isReading($request) ||
            $this->runningUnitTests() ||
            $this->inExceptArray($request) ||
            $this->hasValidOrigin($request) ||
            $this->tokensMatch($request)
        ) {
            return tap($next($request), function ($response) use ($request) {
                if ($this->shouldAddXsrfTokenCookie()) {
                    $this->addCookieToResponse($request, $response);
                }
            });
        }

        throw new TokenMismatchException('CSRF token mismatch.');
    }

    /**
     * Determine if the HTTP request uses a ‘read’ verb.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return bool
     */
    protected function isReading($request)
    {
        return in_array($request->method(), ['HEAD', 'GET', 'OPTIONS']);
    }

    /**
     * Determine if the application is running unit tests.
     *
     * @return bool
     */

View on GitHub (pinned to e0f6eb3518)

Solutions

  1. Ensure the SPA reads the XSRF-TOKEN cookie and sends it as X-XSRF-TOKEN header (axios does this automatically when on the same origin).
  2. Increase session.lifetime in config/session.php to outlast the longest realistic form idle.
  3. Add the route to PreventRequestForgery::$except (or the validateCsrfTokens / except paths) if it is genuinely exempt (e.g. a webhook with its own signature).
  4. Verify SESSION_DOMAIN and SESSION_SECURE_COOKIE match the deployment; mismatched cookie domain silently drops the XSRF cookie.
  5. For APIs, route them under routes/api.php with the Sanctum/Passport token guard so CSRF does not apply.

Example fix

// before: bare fetch, no token
fetch('/profile', { method: 'POST', body: formData });

// after: read XSRF cookie and send header
const token = document.cookie.match(/XSRF-TOKEN=([^;]+)/)?.[1];
fetch('/profile', {
  method: 'POST',
  headers: { 'X-XSRF-TOKEN': decodeURIComponent(token), 'X-Requested-With': 'XMLHttpRequest' },
  body: formData,
});
Defensive patterns

Strategy: validation

Validate before calling

// Frontend: confirm a fresh XSRF cookie exists before submitting
function hasFreshXsrf() {
  return /XSRF-TOKEN=[^;]/.test(document.cookie);
}
if (!hasFreshXsrf()) { location.reload(); /* refresh session cookie */ }

Try / catch

use Illuminate\Session\TokenMismatchException;

try {
    $response = $httpClient->post('/profile', $form);
} catch (TokenMismatchException $e) {
    // typically rendered as 419; re-fetch the page to refresh tokens
}

Prevention

When it happens

Trigger: A POST/PUT/PATCH/DELETE request reaches the middleware without a valid XSRF-TOKEN cookie + X-CSRF-TOKEN/_token header match, AND it is not reading-verb, not in the except array, not from the test runner, and does not satisfy hasValidOrigin(). Typically a form/AJAX submission whose token expired or was never attached.

Common situations: Session lifetime (lifetime in config/session.php) shorter than the time the user spent on a form. Frontend SPA forgot to read the XSRF-TOKEN cookie into axios/fetch headers. Subdomain or cross-origin POST where Sec-Fetch-Site is 'cross-site' or absent. Behind a proxy that strips cookies. Cookie domain misconfigured in session config.

Related errors


AI-assisted analysis of laravel/framework@e0f6eb3518 (2026-08-11). Data as JSON: /api/errors/796147495727edb6. Report an issue: GitHub.