Когда делаешь API для SPA на Laravel, чаще всего возникает вопрос: что брать для авторизации – JWT token или Sanctum token. На первый взгляд оба варианта похожи, потому что и там, и там клиент получает токен или cookie и потом отправляет их на backend. Но внутри логика совсем разная.
JWT token
JWT token – это самостоятельный токен. Он хранит внутри себя данные о пользователе: например id пользователя, срок жизни токена, иногда роли, права, issuer и другие служебные поля. Сервер получает JWT, проверяет подпись и понимает, можно ли доверять этому токену.
Обычно JWT передают в заголовке Authorization:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Sanctum token
Sanctum token работает проще и более по-ларавельному. Сам токен на клиенте не хранит внутри себя данные пользователя. Laravel сохраняет токен в базе данных, обычно в таблице personal_access_tokens, а потом при каждом запросе проверяет: есть ли такой токен, какому пользователю он принадлежит, не истек ли он, какие у него права.
То есть простыми словами: JWT – это пропуск, в котором уже записана информация. Sanctum token – это ключ, который Laravel сверяет со своей базой.
Для SPA в Laravel чаще всего лучше использовать не Bearer token, а Sanctum SPA Authentication через cookie. Это важный момент. Sanctum умеет работать в двух режимах: как API token для мобильных приложений и внешних клиентов, и как cookie-based auth для своего frontend-приложения.
Если frontend и backend принадлежат одному проекту, например frontend на React или Vue, а API на Laravel, то самый нормальный вариант – Sanctum через cookies.
Пример структуры:
Frontend: https://app.site.com
Backend API: https://api.site.com
Или локально:
Frontend: http://localhost:5173
Laravel API: http://localhost:8000
При таком подходе frontend сначала получает CSRF-cookie, потом отправляет login-запрос, Laravel создает обычную сессию, а дальше браузер сам отправляет cookies с каждым запросом.
await axios.get('/sanctum/csrf-cookie');
await axios.post('/login', {
email: '[email protected]',
password: 'password'
});
const response = await axios.get('/api/user');
Чтобы cookies реально уходили с запросами, в axios надо включить withCredentials:
axios.defaults.withCredentials = true;
axios.defaults.withXSRFToken = true;
В Laravel также надо правильно настроить домены, которые считаются stateful. Это нужно, чтобы Sanctum понимал, что запрос идет от твоего SPA, а не от случайного внешнего клиента.
SANCTUM_STATEFUL_DOMAINS=localhost:5173,app.site.com
SESSION_DOMAIN=.site.com
Если frontend и backend на разных поддоменах, SESSION_DOMAIN обычно указывают с точкой перед доменом, чтобы cookie была доступна для поддоменов.
Например:
SESSION_DOMAIN=.example.com
Для API routes, которые должны быть доступны только авторизованному пользователю, можно использовать middleware auth:sanctum:
Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
return $request->user();
});
Если использовать Sanctum именно как Bearer token, например для мобильного приложения, токен создается так:
$token = $user->createToken('mobile-app')->plainTextToken;
return response()->json([
'token' => $token,
]);
Клиент потом отправляет этот токен в заголовке:
Authorization: Bearer 1|qwerty123456789...
Sanctum tokens удобно использовать для мобильных приложений, личных API-ключей, интеграций, ботов, внешних сервисов. То есть там, где cookie-сессия уже не самый удобный вариант.
Еще у Sanctum token можно задавать abilities, то есть условные права доступа.
$token = $user->createToken('admin-token', [
'orders:view',
'orders:update',
])->plainTextToken;
Потом можно проверять, имеет ли токен нужное право:
if ($request->user()->tokenCan('orders:update')) {
// Пользователь может обновлять заказы
}
JWT обычно выбирают в более сложных архитектурах. Например, когда есть отдельный auth-сервис, несколько backend-приложений, микросервисы, независимые API или когда нужно сделать максимально stateless-авторизацию без Laravel-сессий.
Но для обычной SPA на Laravel JWT часто только усложняет проект. Особенно если хранить JWT в localStorage. При XSS-уязвимости злоумышленник может украсть токен и использовать его как настоящий пользователь.
С cookie-based Sanctum auth ситуация обычно спокойнее, потому что можно использовать HttpOnly, SameSite и Secure cookies. Это не делает приложение бессмертным, но для браузерной SPA это более естественная и безопасная схема.
Короткая логика выбора такая:
Свой SPA frontend + Laravel API:
Sanctum SPA auth через cookies
Мобильное приложение:
Sanctum personal access tokens
Внешнее API для партнеров или интеграций:
Sanctum tokens или Passport
Микросервисы / отдельный auth-server / stateless API:
JWT
Если проект обычный: Laravel API плюс React, Vue или Nuxt SPA, то в большинстве случаев лучше начинать с Sanctum SPA Authentication. Это проще, понятнее, лучше ложится на Laravel и не заставляет вручную городить refresh tokens, blacklist, revoke-логику и хранение JWT.
JWT не плохой. Просто его стоит брать тогда, когда есть реальная архитектурная причина. А не потому что “так делают в API”. Для Laravel-проекта со своим frontend Sanctum обычно будет более практичным решением.