# Проблема
В Postman не работает SPA аутентификация на Sanctum. Маршруты с auth:sanctum возвращают 401 статус, даже после успешного логина. В браузере аутентификация работает.
# Причина
Для корректной работы "SPA способа" необходимы некоторые условия, а именно:
- Заголовок Accept (см. «Заголовки для API»)
- Заголовки Referer или Origin
С первым пунктом обычно проблем не возникает, а вот про Referer/Origin знают не все, хотя это есть в документации. Дело в том, что механизм Sanctum подключается вариативно с помощью middleware \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful
И будут ли применены к запросу другие middleware зависит от метода fromFrontend, который получает домен из заголовков Referer или Origin и ищет их среди разрешенных доменов в конфиге sanctum.stateful или SANCTUM_STATEFUL_DOMAINS в env.
Таким образом, если нет заголовков или домен не соответствует разрешенным, то middleware не подключается, а значит не стартует сессия и не работает аутентификация.
# Решение
Необходимо отправлять в Postman заголовок Referer или Origin с разрешенным доменом (на котором находится SPA), указанным в SANCTUM_STATEFUL_DOMAINS.
Например, Origin: https://example.com
# Настройка Postman
Выполнять запросы вручную каждый раз утомительно, необходим предварительный запрос на /sanctum/csrf-cookie и передавать куки в следующем запросе.
Вместо этого можно "автоматизировать" запросы в Postman. Для этого необходимо добавить скрипт на вкладке Pre-request Script.
Обрати внимание, что используется переменная окружения API_URL, её необходимо создать в Postman , либо заменить на свой URL прямо в скрипте.
1if (pm.request.method !== 'GET') { 2 if (pm.environment.get('XSRF-TOKEN')) { 3 pm.request.headers.upsert({ 4 key: 'x-xsrf-token', 5 value: pm.environment.get('XSRF-TOKEN'), 6 }) 7 } else { 8 pm.sendRequest(pm.environment.get('API_URL') + '/sanctum/csrf-cookie', function(error, response) { 9 pm.expect(error).to.equal(null)10 pm.expect(response).to.have.property('code', 204)11 pm.expect(response).to.have.property('status', 'No Content')12 13 let xsrfCookie = response.headers.find(header => header.key.toLowerCase() === 'set-cookie' && header.value.includes('XSRF-TOKEN'))14 15 if (xsrfCookie) {16 let xsrfToken = decodeURIComponent(xsrfCookie.value.split(';')[0].split('=')[1])17 18 pm.request.headers.upsert({19 key: 'x-xsrf-token',20 value: xsrfToken,21 })22 23 pm.environment.set('XSRF-TOKEN', xsrfToken)24 }25 })26 }27}
Не забудь передать заголовки Accept: application/json и Origin с адресом, где находится frontend приложение. Так же убедись, что домен добавлен в SANCTUM_STATEFUL_DOMAINS.
Обрати внимание, что SPA и API приложения могут находиться на разных поддоменах, поэтому в Origin необходимо указывать именно адрес SPA, а не API.