JWT Authentication
JWT (JSON Web Token) ile kimlik doğrulama: token yapısı, çalışma mantığı ve tipik kullanım senaryoları.
JWT, modern web uygulamalarında kimlik doğrulamanın varsayılan aracı haline geldi. Bu yaygınlık iyi bir şey; ama “varsayılan” olması, her durumda doğru seçim olduğu anlamına gelmiyor. Bu yazıda JWT’nin nasıl çalıştığını, ne zaman işe yaradığını ve yıllar içinde gördüğüm tipik hataları aktarıyorum.
JWT nedir, neyi çözer
JWT (JSON Web Token), iki taraf arasında doğrulanabilir biçimde bilgi taşıyan bir token formatıdır. Nokta ile ayrılmış üç bölümden oluşur:
header.payload.signature
header token türünü ve imzalama algoritmasını söyler; payload taşınan veriyi tutar; signature ise ilk iki bölümün gizli bir anahtarla imzalanmış halidir. İmza sayesinde sunucu, token içeriğinin değiştirilmediğini — anahtarı kimseyle paylaşmadan — doğrulayabilir.
JWT’nin çözdüğü asıl problem şu: sunucu, oturum bilgisini kendi tarafında saklamak zorunda kalmaz. Token kendi kendini doğrular. Bu, birden çok sunucuya yayılmış bir sistemde oturumu paylaşma derdini ortadan kaldırır.
Bedeli ne
Bu durumsuzluk bedava değil. Stateful bir oturumda kullanıcıyı anında atabilirsiniz — kaydı silersiniz, biter. JWT’de token, siz ne yaparsanız yapın, süresi dolana kadar geçerlidir. Ele geçirilmiş bir token’ı geri çağırmak, JWT’nin doğası gereği zordur.
Bu yüzden JWT’yi şöyle konumlandırıyorum: kısa ömürlü erişim için iyi; “oturumu her an anında iptal edebilmem gerek” diyen senaryolar için zayıf.
Bu zayıflığı bir kara liste (blacklist) ile yamayabilirsiniz — iptal edilen token’ları bir yerde tutup her istekte kontrol edersiniz. Ama dikkat edin: o an JWT’nin baştaki vaadini, yani “sunucu hiçbir oturum durumu tutmasın” ilkesini terk etmiş olursunuz. Kara liste eklediğiniz noktada, durumsuzluğun getirdiği kolaylığın bir kısmını geri vermiş olursunuz. Bu kötü bir karar değil; ama bilinçli verilmesi gereken bir karar.
Pratikte: imzalama ve doğrulama
Konuyu somutlaştırmak için imzalama ve doğrulamayı elle yapan küçük bir sınıf. Production’da bunu kendiniz yazmayın — firebase/php-jwt gibi denenmiş bir paket kullanın; aşağıdaki yalnızca mekanizmayı göstermek için:
class JWT
{
protected const ALGORITHM = 'HS256';
protected const SIGNATURE_ALGORITHM = 'sha256';
public static function encode(string $key, array $payload, ?int $ttl = null): string
{
$header = base64_encode(json_encode([
'typ' => 'JWT',
'alg' => self::ALGORITHM,
]));
$payload = base64_encode(json_encode([
'data' => $payload,
'created_at' => time(),
'ttl' => $ttl,
]));
return $header . '.' . $payload . '.' . self::signature($key, $header, $payload);
}
public static function decode(string $key, string $jwt): array|false
{
try {
[$h, $p, $signature] = explode('.', $jwt);
if (!hash_equals(self::signature($key, $h, $p), $signature)) {
return false;
}
$payload = json_decode(base64_decode($p), true);
if ($payload['ttl'] !== null && time() - $payload['created_at'] > $payload['ttl']) {
return false;
}
return $payload['data'];
} catch (\Throwable) {
return false;
}
}
private static function signature(string $key, string $header, string $payload): string
{
return base64_encode(hash_hmac(self::SIGNATURE_ALGORITHM, $header . '.' . $payload, $key, true));
}
}
Burada gözden kaçmaması gereken bir satır var: imza karşılaştırmasını hash_equals() ile yapıyorum, == ile değil. Sıradan karşılaştırma, yanıt süresinden bilgi sızdıran zamanlama saldırılarına (timing attack) açıktır. Küçük bir detay; ama güvenlik kodunda “küçük detay” diye bir şey yok.
Yıllar içinde gördüğüm hatalar
- Uzun ömürlü token. Erişim token’ı 15 dakika–1 saat arası olmalı; kalıcı oturum için ayrı, daha uzun ömürlü bir refresh token kullanın.
- Yanlış yerde saklamak. Token’ı
localStorage’a koymak onu XSS’e açar.HttpOnlyveSecurebir cookie daha güvenlidir. - Payload’a hassas veri koymak.
payloadimzalıdır ama şifreli değildir — Base64 çözen herkes okuyabilir. Parola, kimlik numarası gibi şeyler oraya yazılmaz. alg: noneihtimalini unutmak. Doğrulama tarafı algoritmayı token’ın kendisinden körü körüne okursa, saldırgan imzayı tamamen atlayabilir. Beklediğiniz algoritmayı kodda sabitleyin, token’a güvenmeyin.
Özet
JWT zarif bir mekanizma; ama sihir değil. Durumsuzluğun getirdiği ölçeklenme kolaylığını, iptal etme zorluğu olarak geri ödüyorsunuz. Token’ları kısa tutarsanız, doğru yerde saklarsanız ve imzayı titizce doğrularsanız, bu takas çoğu uygulama için makul. Bu koşulları sağlayamıyorsanız, klasik sunucu oturumu hâlâ saygın bir seçenektir — yeni olan, her zaman daha iyi anlamına gelmiyor.