{"record":{"id":"796147495727edb6","repo":"laravel/framework","slug":"csrf-token-mismatch","errorCode":null,"errorMessage":"CSRF token mismatch.","messagePattern":"CSRF token mismatch\\.","errorType":"http","errorClass":"TokenMismatchException","httpStatus":419,"severity":"warning","filePath":"src/Illuminate/Foundation/Http/Middleware/PreventRequestForgery.php","lineNumber":111,"sourceCode":"     * @throws \\Illuminate\\Http\\Exceptions\\OriginMismatchException\n     */\n    public function handle($request, Closure $next)\n    {\n        if (\n            $this->isReading($request) ||\n            $this->runningUnitTests() ||\n            $this->inExceptArray($request) ||\n            $this->hasValidOrigin($request) ||\n            $this->tokensMatch($request)\n        ) {\n            return tap($next($request), function ($response) use ($request) {\n                if ($this->shouldAddXsrfTokenCookie()) {\n                    $this->addCookieToResponse($request, $response);\n                }\n            });\n        }\n\n        throw new TokenMismatchException('CSRF token mismatch.');\n    }\n\n    /**\n     * Determine if the HTTP request uses a ‘read’ verb.\n     *\n     * @param  \\Illuminate\\Http\\Request  $request\n     * @return bool\n     */\n    protected function isReading($request)\n    {\n        return in_array($request->method(), ['HEAD', 'GET', 'OPTIONS']);\n    }\n\n    /**\n     * Determine if the application is running unit tests.\n     *\n     * @return bool\n     */","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/laravel/framework/blob/e0f6eb3518ac29fbbca8529e97d0df7fc9f24481/src/Illuminate/Foundation/Http/Middleware/PreventRequestForgery.php#L93-L129","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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).","Increase session.lifetime in config/session.php to outlast the longest realistic form idle.","Add the route to PreventRequestForgery::$except (or the validateCsrfTokens / except paths) if it is genuinely exempt (e.g. a webhook with its own signature).","Verify SESSION_DOMAIN and SESSION_SECURE_COOKIE match the deployment; mismatched cookie domain silently drops the XSRF cookie.","For APIs, route them under routes/api.php with the Sanctum/Passport token guard so CSRF does not apply."],"exampleFix":"// before: bare fetch, no token\nfetch('/profile', { method: 'POST', body: formData });\n\n// after: read XSRF cookie and send header\nconst token = document.cookie.match(/XSRF-TOKEN=([^;]+)/)?.[1];\nfetch('/profile', {\n  method: 'POST',\n  headers: { 'X-XSRF-TOKEN': decodeURIComponent(token), 'X-Requested-With': 'XMLHttpRequest' },\n  body: formData,\n});","handlingStrategy":"validation","validationCode":"// Frontend: confirm a fresh XSRF cookie exists before submitting\nfunction hasFreshXsrf() {\n  return /XSRF-TOKEN=[^;]/.test(document.cookie);\n}\nif (!hasFreshXsrf()) { location.reload(); /* refresh session cookie */ }","typeGuard":null,"tryCatchPattern":"use Illuminate\\Session\\TokenMismatchException;\n\ntry {\n    $response = $httpClient->post('/profile', $form);\n} catch (TokenMismatchException $e) {\n    // typically rendered as 419; re-fetch the page to refresh tokens\n}","preventionTips":["Use axios with withCredentials on same-origin — it auto-attaches X-XSRF-TOKEN.","Set session.lifetime generously relative to longest form idle.","Keep SESSION_DOMAIN and SESSION_SECURE_COOKIE aligned with deployment.","Route stateless API consumers under the api guard / Sanctum, not web."],"tags":["csrf","laravel","security","session","middleware"],"backgroundTag":null,"analyzedSha":"e0f6eb3518ac29fbbca8529e97d0df7fc9f24481","analyzedAt":"2026-08-11T20:52:37.562Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}