{"record":{"id":"961879e6b253b95c","repo":"laravel/framework","slug":"origin-mismatch","errorCode":null,"errorMessage":"Origin mismatch.","messagePattern":"Origin mismatch\\.","errorType":"http","errorClass":"OriginMismatchException","httpStatus":403,"severity":"warning","filePath":"src/Illuminate/Foundation/Http/Middleware/PreventRequestForgery.php","lineNumber":156,"sourceCode":"     * @param  \\Illuminate\\Http\\Request  $request\n     * @return bool\n     *\n     * @throws \\Illuminate\\Http\\Exceptions\\OriginMismatchException\n     */\n    protected function hasValidOrigin($request)\n    {\n        $secFetchSite = $request->header('Sec-Fetch-Site');\n\n        if ($secFetchSite === 'same-origin') {\n            return true;\n        }\n\n        if ($secFetchSite === 'same-site' && static::$allowSameSite) {\n            return true;\n        }\n\n        if (static::$originOnly) {\n            throw new OriginMismatchException('Origin mismatch.');\n        }\n\n        return false;\n    }\n\n    /**\n     * Determine if the session and input CSRF tokens match.\n     *\n     * @param  \\Illuminate\\Http\\Request  $request\n     * @return bool\n     */\n    protected function tokensMatch($request)\n    {\n        $token = $this->getTokenFromRequest($request);\n\n        return is_string($request->session()->token()) &&\n               is_string($token) &&\n               hash_equals($request->session()->token(), $token);","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/laravel/framework/blob/e0f6eb3518ac29fbbca8529e97d0df7fc9f24481/src/Illuminate/Foundation/Http/Middleware/PreventRequestForgery.php#L138-L174","documentation":"Within hasValidOrigin(), if the Sec-Fetch-Site header is neither 'same-origin' nor (when allowed) 'same-site', and the static flag PreventRequestForgery::$originOnly is true, an OriginMismatchException is thrown. This is the strict, token-free mode that relies purely on the browser's Fetch Metadata to deny cross-origin requests. Unlike TokenMismatchException it is not auto-converted to 419; it surfaces as a 403.","triggerScenarios":"originOnly mode is enabled (e.g. PreventRequestForgery::originOnly()) AND a request arrives with Sec-Fetch-Site: cross-site or no Sec-Fetch-Site header at all. Common with non-browser clients (curl, Postman, server-to-server) that never send Fetch Metadata headers.","commonSituations":"Mixing originOnly strict mode with API/webhook consumers that are not browsers. Browsers that suppress Sec-Fetch-Site (older versions, some privacy extensions). Webhooks from third parties hitting originOnly-guarded routes.","solutions":["Move API/webhook routes out of the web middleware stack (use api guard or Sanctum) so PreventRequestForgery does not run on them.","If same-site subdomain requests must pass, enable PreventRequestForgery::allowSameSite().","Add the affected URIs to $except and protect them with a different mechanism (signature, bearer token).","Turn off originOnly if you genuinely need cross-origin browser requests: PreventRequestForgery::originOnly(false)."],"exampleFix":"// before\nPreventRequestForgery::originOnly();\n// webhook POST from third party -> OriginMismatchException\n\n// after — exclude the webhook, validate signature separately\nPreventRequestForgery::except(['/webhooks/stripe']);\n// and in the controller, abort_unless(hash_equals($known, $sig), 403);","handlingStrategy":"validation","validationCode":"// On the caller side, only send state-changing requests from a browser same-origin context,\n// or move API/webhook routes out of the PreventRequestForgery middleware.\nPreventRequestForgery::except(['/api/*', '/webhooks/*']);","typeGuard":"// Server-side guard for non-browser callers: rely on bearer tokens instead of Fetch Metadata\nif ($request->bearerToken() && $request->user('sanctum')) { /* bypass origin check */ }","tryCatchPattern":"use Illuminate\\Http\\Exceptions\\OriginMismatchException;\n\ntry {\n    $response = $next($request);\n} catch (OriginMismatchException $e) {\n    // surface 403; do NOT widen trust — fix routing or use bearer auth\n}","preventionTips":["Do not enable originOnly for routes consumed by non-browser clients.","Allow same-site subdomains with PreventRequestForgery::allowSameSite() when needed.","Prefer Sanctum bearer tokens for cross-origin API access.","Document which routes are browser-only so backend consumers know to use the API stack."],"tags":["csrf","laravel","security","origin","fetch-metadata"],"backgroundTag":null,"analyzedSha":"e0f6eb3518ac29fbbca8529e97d0df7fc9f24481","analyzedAt":"2026-08-11T20:52:37.562Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}