# Laravel 7 ve Sanctum ile SPA kimlik doğrulama

> Laravel Sanctum'un SPA kimlik doğrulamasını nasıl çözdüğünü, token tabanlı yaklaşımdan farkını somut örneklerle anlatıyorum.

- Yayın: 2020-03-01
- Kategori: Web Geliştirme
- Etiketler: Laravel, API
- Okuma süresi: 3 dk okuma
- Kaynak: https://www.muhammetsafak.com.tr/blog/laravel-7-ve-sanctum-ile-spa-kimlik-dogrulama/
- Dil: tr-TR
- Yazar: Muhammet Şafak

---
SPA geliştirirken kimlik doğrulama her zaman rahatsız edici bir soruydu: oturum mu kullanayım, token mi? Laravel Passport büyük projeler için güçlü ama fazla ağır. JWT kütüphaneleri işe yarıyor ama her birinin kendine özgü ince noktaları var. Laravel 7 ile birlikte resmi olarak gelen Sanctum bu denklemi değiştirdi.

## Sorun neydi?

Bir [Vue SPA'sı](/blog/vue-router-ile-tek-sayfa-uygulama-spa-mantigi) ile aynı domain üzerindeki [Laravel API'si](/blog/laravel-ile-json-api-uclari-yazmak) arasında oturum yönetimi yapmak istiyorsunuz. Klasik `web` kimlik doğrulaması bu durumda çalışmıyor: SPA ayrı bir süreçte çalışıyor, `laravel_session` çerezi API isteklerine otomatik eklemiyor. Token tabanlı yaklaşımda ise tokeni güvenli saklamak (localStorage tehlikeli, httpOnly çerez elle kurulması gereken başka bir iş) ve yenilemek ayrı bir yük oluyor.

Sanctum iki senaryoya ayrı cevap veriyor: aynı kök domain (same-site) için çerez tabanlı oturum, mobil/üçüncü taraf için kişisel erişim token'ı. SPA için birinci yol daha temiz.

## Kurulum ve yapılandırma

```bash
composer require laravel/sanctum
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
php artisan migrate
```

`api` middleware grubuna Sanctum'un middleware'ini eklemek gerekiyor:

```php
// app/Http/Kernel.php
'api' => [
    \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
    'throttle:60,1',
    \Illuminate\Routing\Middleware\SubstituteBindings::class,
],
```

`config/sanctum.php`'deki `stateful` dizisine SPA'nın adresini ekliyorsunuz:

```php
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', 'localhost,127.0.0.1')),
```

## Oturum açma akışı

SPA tarafında önce CSRF çerezi alınıyor, ardından kimlik bilgileri gönderiliyor:

```javascript
// Önce CSRF çerezini al
await axios.get('/sanctum/csrf-cookie');

// Sonra giriş isteği
await axios.post('/login', {
    email: this.email,
    password: this.password,
});
```

`/sanctum/csrf-cookie` isteği, Sanctum'un `XSRF-TOKEN` çerezini tarayıcıya bırakıyor. Axios bunu otomatik olarak sonraki her istekte `X-XSRF-TOKEN` başlığı olarak gönderiyor. Laravel bu başlığı doğrulayarak CSRF saldırılarını önlüyor.

Giriş başarılı olursa Laravel oturumu sunucu tarafında başlatıyor ve oturum çerezi tarayıcıya dönüyor. Bundan sonraki her API isteği bu çerezi taşıdığı için kimlik doğrulanmış sayılıyor.

Korunan rotalarda `auth:sanctum` guard'ı kullanılıyor:

```php
Route::middleware('auth:sanctum')->group(function () {
    Route::get('/user', fn () => auth()->user());
    Route::apiResource('posts', PostController::class);
});
```

## Token tabanlı yaklaşımla karşılaştırma

Sanctum'un çerez modeli SPA için neden daha iyi? Birkaç somut neden:

Token saklamak için güvenli bir yer bulmak zorundasınız. `localStorage` XSS saldırılarına açık; `httpOnly` çerez güvenli ama o zaten çerez kullanıyorsunuz. Sanctum, Laravel'in yerleşik oturum altyapısını kullandığı için bu kararı sizi vermenize gerek kalmıyor.

Token refresh mekanizması yok. Sanctum'un çerez modeli [standart Laravel oturumu](/blog/laravel-5-2-coklu-kimlik-dogrulama-ve-route-gruplari) gibi davranıyor; oturum süresi sunucuda yönetiliyor.

Aynı domain koşulu önemli. SPA ve API farklı subdomainlerde olabilir (`app.example.com` ve `api.example.com`), ama farklı ana domainlerde olamaz. Bu sınırın dışına çıktığınızda Sanctum token modeline geçmek gerekiyor.

## Subdomain yapılandırması ve sık karşılaşılan tuzak

Geliştirme ortamında her şey çalışıp production'da kimlik doğrulama aniden başarısız olduğunda ilk bakacağınız yer `SANCTUM_STATEFUL_DOMAINS` değişkeni. `.env` dosyasında port numarasını eklemeyi unutmak çok sık yaşanan bir hata:

```
# Yanlış
SANCTUM_STATEFUL_DOMAINS=app.example.com

# Doğru (geliştirme ortamı için)
SANCTUM_STATEFUL_DOMAINS=localhost:3000,127.0.0.1:3000
```

Bunun yanı sıra `SESSION_DOMAIN` değişkenini subdomain kullanıyorsanız `.example.com` (baştaki nokta dahil) olarak ayarlamak gerekiyor; aksi hâlde çerez yalnızca `api.example.com`'a gönderiliyor, `app.example.com`'a değil.

## Çıkış ve oturum yönetimi

Çıkış yapmak için `/logout` rotasına POST istek atmak yeterli; Laravel oturumu geçersiz kılıyor:

```php
Route::post('/logout', function (Request $request) {
    Auth::guard('web')->logout();
    $request->session()->invalidate();
    $request->session()->regenerateToken();
    return response()->noContent();
});
```

---

Sanctum, SPA kimlik doğrulama sorununa Laravel'e özgü, sade bir cevap sunuyor. Passport kadar kapsamlı değil — OAuth2 flow'larına ihtiyacınız varsa yanlış araç. Ama kendi SPA'nızla kendi API'niz arasındaki oturumu güvenli kurmak için tam ölçek bu.
