Ваше API на Laravel работает.

Ваши учетные данные верны.

 /sanctum/csrf-cookie  может даже возвращать  204 .

Затем вы отправляете запрос на вход:

 POST /login
 

и Laravel отвечает:

 419 Page Expired
 

Если вы меняли случайные настройки CORS в надежде, что ошибка исчезнет, остановитесь.

Ошибка  Laravel Sanctum 419 обычно связана с проблемами CSRF или сессионной аутентификации, и самый быстрый способ исправить ее — точно определить, на каком этапе ломается поток аутентификации Sanctum.

Вот порядок отладки, который я использую.


Кратко (TL;DR)

Для SPA-аутентификации в Laravel Sanctum проверьте следующие пять вещей:

 1. Stateful middleware
2. SANCTUM_STATEFUL_DOMAINS
3. CORS credentials
4. Session cookies
5. Axios CSRF handling
 

И всегда отправляйте запрос:

 GET /sanctum/csrf-cookie
 

перед:

 POST /login
 

Если хотя бы одно звено в этой цепочке настроено неверно, Laravel может ответить ошибкой  419 CSRF token mismatch / Page Expired.


1. Поймите, что на самом деле означает ошибка 419

При использовании SPA-аутентификации в Laravel Sanctum Laravel полагается на обычные куки сессий и защиту от CSRF.

Взаимодействие с браузером выглядит примерно так:

 Frontend
   |
   | GET /sanctum/csrf-cookie
   v
Laravel
   |
   | Sets XSRF-TOKEN
   | Sets session cookie
   v
Browser
   |
   | POST /login
   | Cookie + X-XSRF-TOKEN
   v
Laravel validates request
 

Когда Laravel не может проверить эту связь между CSRF и сессией, вы можете получить:

 419 Page Expired
 

Так что вопрос звучит не просто как:

"Правильна ли моя конфигурация CORS?"

Лучший вопрос:

"На каком именно этапе ломается цепочка аутентификации?"


2. Начните с панели Network в браузере

Прежде чем менять  .env , Axios или конфигурацию Laravel, откройте:

 Chrome DevTools → Network

Затем выполните вход повторно.

Найдите  первый запрос, который ведет себя не так, как ожидалось.

Случай А: Ошибка OPTIONS

Если браузер блокирует запрос  OPTIONS , в первую очередь исследуйте CORS.

Случай Б: Ошибка  /sanctum/csrf-cookie 

Ваш браузер не может успешно инициализировать защиту Sanctum от CSRF.

Случай В: Запрос CSRF успешен, но  /login  возвращает 419

Здесь я бы проверил:

  •  XSRF-TOKEN 
  • Куки сессии Laravel
  •  X-XSRF-TOKEN 
  • Домен кук
  • Учетные данные в Axios
  • Stateful-домены Sanctum

Случай Г: Вход успешен, но  /api/user  возвращает 401

Теперь проблема, скорее всего, связана с аутентифицированной сессией или с тем, что Sanctum не распознает запрос как stateful.

Эта простая классификация избавляет от множества лишних поисков ошибок.


3. Убедитесь, что Sanctum считает SPA stateful-приложением

Современные приложения на Laravel могут включать stateful API middleware для Sanctum в файле  bootstrap/app.php .

Например:

 use Illuminate\Foundation\Configuration\Middleware;

->withMiddleware(function (Middleware $middleware): void {
    $middleware->statefulApi();
})
 

Это важно, потому что Sanctum должен понимать, что запросы от вашего собственного SPA должны использовать аутентификацию на основе сессий.

Если вы следуете старому руководству по Laravel, вы можете увидеть инструкции с упоминанием:

 app/Http/Kernel.php
 

Будьте осторожны.

Структура приложения Laravel эволюционировала, поэтому старые туториалы по Sanctum могут указывать на файлы конфигурации, которые не подходят для новых приложений Laravel.


4. Проверьте  SANCTUM_STATEFUL_DOMAINS 

Предположим, ваша конфигурация выглядит так:

 Frontend:
https://app.example.com

API:
https://api.example.com
 

Хост вашего SPA должен распознаваться как stateful.

Например:

 SANCTUM_STATEFUL_DOMAINS=app.example.com
 

Одна из распространенных ошибок — добавление протокола:

 SANCTUM_STATEFUL_DOMAINS=https://app.example.com
 

Обычно здесь требуется совсем не это.

Думайте о  хосте, а не об URL фронтенда.


Локальный хост (localhost) может быть еще сложнее

Допустим, Vite запускается на:

 http://localhost:5173
 

Тогда вам может понадобиться:

 SANCTUM_STATEFUL_DOMAINS=localhost:5173
 

Не смешивайте бездумно:

 localhost
127.0.0.1
localhost:5173
127.0.0.1:5173
 

Используйте одну и ту же схему для разработки.

Удивительное количество багов в Sanctum происходит из-за мельчайших различий в именах хостов.


5. CORS должен разрешать учетные данные (credentials)

Если ваша SPA-аутентификация использует куки, конфигурация CORS должна разрешать запросы с учетными данными.

Типичная конфигурация может включать:

 return [

    'paths' => [
        'api/*',
        'sanctum/csrf-cookie',
        'login',
        'logout',
    ],

    'allowed_methods' => ['*'],

    'allowed_origins' => [
        'https://app.example.com',
    ],

    'allowed_headers' => ['*'],

    'supports_credentials' => true,

];
 

Важный параметр:

 'supports_credentials' => true,
 

И не делайте так бездумно:

 'allowed_origins' => ['*']
 

когда вы полагаетесь на куки с учетными данными.

Укажите origin фронтенда явно:

 https://app.example.com
 

Origin и домен — это не одно и то же

Для CORS:

 https://app.example.com
 

— это  origin (источник).

Схема имеет значение.

Это разные origins:

 http://app.example.com
https://app.example.com
 

Между тем, настройка stateful-доменов в Sanctum относится к нужному хосту/домену.

Смешение этих понятий — одна из причин, почему конфигурация Sanctum поначалу кажется запутанной.


6. Проверьте конфигурацию кук сессии

Теперь предположим, что ваша архитектура такова:

 app.example.com
api.example.com
 

Обе находятся под управлением:

 example.com
 

Типичная конфигурация сессии для продакшена может включать:

 SESSION_DOMAIN=.example.com
SESSION_SECURE_COOKIE=true
SESSION_SAME_SITE=lax
 

Конфигурация кук для родительского домена позволяет сессии работать на соответствующих субдоменах.

После изменения настроек окружения также помните, что закэшированная конфигурация может заставить вас думать, что изменения не работают.

В зависимости от вашего рабочего процесса деплоя, вовремя очищайте кэш конфигурации Laravel.

Например:

 php artisan config:clear
 

и пересоздавайте кэш конфигурации в соответствии с вашим процессом деплоя на продакшен.


7. Правильно настройте Axios

Ваша настройка Laravel может быть идеальной и все равно выдавать ошибку, если фронтенд никогда не отправляет куки обратно.

Для Axios:

 import axios from 'axios';

const api = axios.create({
  baseURL: import.meta.env.VITE_API_URL,
  withCredentials: true,
  withXSRFToken: true,
  headers: {
    Accept: 'application/json',
  },
});
 

Перед входом в систему:

 await api.get('/sanctum/csrf-cookie');

await api.post('/login', {
  email,
  password,
});
 

Два важных параметра Axios:

 withCredentials: true
 

и:

 withXSRFToken: true
 

Теперь загляните в браузер.

После:

 GET /sanctum/csrf-cookie
 

вы обычно должны видеть соответствующие CSRF/сессионные куки.

Затем проверьте:

 POST /login
 

и убедитесь, что данные аутентификации действительно отправляются обратно в Laravel.


Лучший способ отладки ошибки 419

Вместо того чтобы одновременно менять Laravel, CORS, Axios, куки и middleware, используйте эту последовательность.

Тест 1 — CSRF-эндпоинт

Запрос:

 GET /sanctum/csrf-cookie
 

Ожидаемый результат:

 Successful response
+
XSRF/session cookies created
 

Если куки не появляются, пока не отлаживайте контроллер входа.


Тест 2 — Запрос на вход

Запрос:

 POST /login
 

Проверьте:

 Are cookies attached?
Is X-XSRF-TOKEN present?
Is the request being blocked by CORS?
 

Если ответ отрицательный, вы существенно сузили круг поиска проблемы.


Тест 3 — Эндпоинт, требующий аутентификации

После успешного входа:

 GET /api/user
 

Если вход прошел успешно, но этот запрос возвращает:

 401 Unauthenticated
 

сосредоточьтесь на:

 Sanctum stateful configuration
Session cookie
Cookie domain
withCredentials
Middleware
 

а не на CSRF.


419 против 401 против 422

Эти ошибки часто путают друг с другом.

419

Обычно проверяйте:

 CSRF
XSRF token
Cookies
Session
 

401

Обычно проверяйте:

 Authentication
Session recognition
Sanctum stateful requests
Missing credentials
 

422

Обычно проверяйте:

 Validation errors
Missing fields
Invalid input
 

Понимание разницы может сэкономить поразительно много времени.


Почему Sanctum работает в Postman, но падает в Chrome?

Это крайне распространенная ситуация:

 Postman ✅
Browser ❌
 

И это важный знак.

Браузеры применяют:

  • CORS
  • политики работы с куки
  • origins (источники)
  • учетные данные
  • поведение SameSite
  • CSRF-потоки

API-клиенты вроде Postman ведут себя совсем не так, как страница в браузере.

Поэтому, если API работает из Postman, но выдает ошибку из React/Vue/Vite, начинайте исследовать  поток аутентификации в браузере, а не учетные данные вашей базы данных.


Не «исправляйте» ошибку 419 отключением CSRF

Вы можете найти в сети решения, предлагающие исключить эндпоинт входа из защиты CSRF.

Это может заставить ошибку исчезнуть.

Но это не обязательно означает, что вы починили Sanctum.

Для сессионной аутентификации в собственном SPA лучшим решением является правильная настройка:

 CSRF
Session cookies
Stateful domains
CORS
Frontend credentials
 

а не удалять защиту, которая обнажила проблему с конфигурацией.


Одна важная деталь архитектуры продакшена, которую часто упускают

Эта настройка:

 app.example.com
api.example.com
 

сильно отличается от:

 my-app.vercel.app
api.example.com
 

В первом примере фронтенд и бэкенд используют один и тот же сайт верхнего уровня.

Во втором — они находятся на несвязанных доменах.

CORS не может волшебным образом превратить несвязанные домены в единое окружение first-party cookies.

Поэтому, если вы боретесь с аутентификацией на основе cookies в Sanctum на совершенно разных продакшн-доменах, пересмотрите саму архитектуру.

Кастомный домен фронтенда, такой как:

 app.example.com
 

может сделать настройку first-party для Sanctum значительно более аккуратной.


Мой чек-лист для Sanctum 419 за 60 секунд

Прежде чем снова искать в Stack Overflow, проверьте это:

 [ ] statefulApi() enabled

[ ] SPA exists in SANCTUM_STATEFUL_DOMAINS

[ ] Exact frontend origin allowed by CORS

[ ] supports_credentials = true

[ ] Correct SESSION_DOMAIN

[ ] Secure cookie configuration matches HTTPS setup

[ ] Axios withCredentials = true

[ ] Axios withXSRFToken = true

[ ] /sanctum/csrf-cookie called before login

[ ] XSRF-TOKEN appears in browser

[ ] Session cookie appears in browser

[ ] Login request sends cookies

[ ] X-XSRF-TOKEN is sent correctly
 

Если все двенадцать пунктов верны, вы исключили большинство частых причин ошибки 419 в Laravel Sanctum.


Порядок отладки важнее самого исправления

Главный урок заключается вовсе не в конкретной настройке в  .env .

А в следующем:

 Отлаживайте первый сломанный запрос, вместо того чтобы наугад менять конфигурацию аутентификации.

Используйте следующий порядок:

 OPTIONS
   ↓
/sanctum/csrf-cookie
   ↓
Cookies
   ↓
POST /login
   ↓
/api/user
 

Найдите, где прекращается ожидаемое поведение.

Обычно именно там и начинается ваша настоящая проблема.


Нужен полный справочник по ошибке 419 в Laravel Sanctum?

Я написал более подробное руководство, охватывающее Laravel Sanctum CORS, CSRF-cookies, настройку Axios, продакшн-домены, проблемы с localhost, настройку сессий, ошибки 401 против 419 против 422, а также устранение неполадок при деплое.

👉  Читайте полное руководство по исправлению ошибки CORS 419 в Laravel Sanctum

Используйте полное руководство, если быстрый чек-лист выше не помог сразу выявить проблему.


Если вы занимаетесь отладкой Sanctum прямо сейчас, помните:

 419 — это симптом. Поток запросов браузера подскажет вам причину.