Refresh token nedir?
Refresh token, kısa ömürlü access token sona erdiğinde kullanıcıyı yeniden girişe zorlamadan yeni bir access token alınmasını sağlayan uzun ömürlü kimlik bilgisidir. Access token API isteğinde taşınır; refresh token ise yalnız token yenileme uç noktasına gönderilir. Bu ayrım, ele geçirilen bir access tokenın kullanılabileceği süreyi kısaltır.
Refresh token bir “sonsuz oturum anahtarı” değildir. TLS ile taşınmalı, istemci ve yetki kapsamına bağlanmalı, tahmin edilemez olmalı, sunucu tarafında iptal edilebilmeli ve hareketsizlik sonunda sona ermelidir. Public client için RFC 9700, tokenı gönderen istemciye kriptografik olarak bağlamayı veya her yenilemede refresh token rotation uygulamayı zorunlu güvenlik seçenekleri olarak tanımlar.
Access token ile refresh token arasındaki fark
| Özellik | Access token | Refresh token |
|---|---|---|
| Amaç | API kaynağına erişim | Yeni access token alma |
| Gönderildiği yer | Korunan API endpointleri | Yalnız token endpointi |
| Ömür | Kısa | Daha uzun, politikaya bağlı |
| İçerik | JWT veya opaque olabilir | Opaque ya da bütünlüğü korunan yapı olabilir |
| Sunucu kaydı | Her tasarımda zorunlu değil | İptal, rotation ve reuse detection için gerekir |
| Ele geçirilme etkisi | Süresi ve kapsamıyla sınırlı | Yeni access token üretebildiği için daha kritiktir |
Access tokenın kısa tutulması tek başına yeterli değildir. Audience, issuer, imza, süre, kullanıcı durumu, oturum ve yetki sürümü her istekte doğrulanmalıdır.
JWT refresh token mıdır?
JWT bir veri biçimidir; refresh tokenın görevi değildir. Access token JWT olabilir. Refresh token da JWT olarak üretilebilir, ancak zorunlu değildir. Uygulama içi oturum yenilemede rastgele üretilmiş opaque token kullanmak, token içeriğini istemciye açıklamadan sunucuda hash, family ve iptal durumu tutmayı kolaylaştırır.
Bu projede refresh token kriptografik rastgele üretilir ve veritabanında açık değer yerine hash saklanır. İstemcinin sunduğu değer tekrar hashlenerek kayıt aranır.
Güvenli yenileme akışı
- Kullanıcı doğrulandıktan sonra kısa ömürlü access token ve rastgele refresh token üret.
- Refresh tokenın yalnız hashini; kullanıcı, session, family, expiry ve güvenlik sürümüyle kaydet.
- Yenileme isteğinde tokenı hashle ve kaydı transaction içinde kilitle.
- Kayıt yoksa, süresi dolmuşsa, kullanıcı pasifse veya yetki sürümü değişmişse isteği reddet.
- Kullanılmış ya da iptal edilmiş token tekrar geldiyse token ailesini iptal et.
- Geçerli tokenı iptal edilmiş olarak işaretle ve yerine yeni refresh token kaydı ekle.
- Transaction başarıyla tamamlandıktan sonra yeni access + refresh token çiftini dön.
Tek kullanımlık davranış eşzamanlı iki yenileme isteğinde de korunmalıdır. HDYBlog API
bu nedenle mevcut tokenı Serializable transaction ve UPDLOCK, ROWLOCK ile okur;
eski kaydı iptal etme ve yeni kaydı ekleme aynı transaction içinde yapılır.
ASP.NET Core rotation iskeleti
Aşağıdaki parça projenin çalışan AuthService.RefreshTokenAsync akışının sadeleştirilmiş
iskeletidir. Token değeri SQL metnine eklenmez; Dapper parametresi olarak taşınır.
var tokenHash = tokenService.HashRefreshToken(refreshToken);
await using var connection = await connectionFactory.CreateConnectionAsync(ct);
await using var transaction = await connection.BeginTransactionAsync(
IsolationLevel.Serializable, ct);
var current = await connection.QueryFirstOrDefaultAsync<RefreshToken>(
new CommandDefinition(
"""
SELECT TOP (1) rt.*
FROM dbo.RefreshTokens rt WITH (UPDLOCK, ROWLOCK)
WHERE rt.TokenHash = @TokenHash
AND rt.DeletedAt IS NULL;
""",
new { TokenHash = tokenHash }, transaction, cancellationToken: ct));
if (current is null)
return null;
if (current.RevokedAt is not null)
{
await RevokeFamilyAsync(connection, transaction, current.FamilyId, ct);
await transaction.CommitAsync(ct);
return null;
}
var nextToken = tokenService.GenerateRefreshToken();
var nextHash = tokenService.HashRefreshToken(nextToken);
// Eski kaydı iptal et ve yeni family üyesini aynı transaction içinde ekle.
await RotateAsync(connection, transaction, current, nextHash, ct);
await transaction.CommitAsync(ct);
Gerçek uygulamada kullanıcı aktifliği, expiry, token version, iki faktör doğrulama durumu, issuer/audience ve session kaydı da doğrulanır.
Refresh token rotation nedir?
Rotation, her başarılı yenilemede yeni refresh token üretip kullanılan tokenı geçersiz
kılmaktır. Eski ve yeni kayıt aynı FamilyId ile bağlanır. Böylece eski token tekrar
sunulduğunda bunun normal bir yenileme değil replay olabileceği anlaşılır.
Rotation işlemi atomik değilse iki paralel istek iki geçerli yeni token üretebilir. Transaction, benzersiz hash ve kaydın güncelleme kilidi bu yarış durumunu önler.
Reuse detection ve token ailesi
Eski refresh tokenın ikinci kez kullanılması “hangi taraf saldırgan?” sorusunu kesin cevaplamaz. Meşru istemci ve tokenı ele geçiren kişi aynı eski değeri sunabilir. Güvenli tepki, aktif token ailesini iptal etmek ve kullanıcıdan yeniden kimlik doğrulaması istemektir.
Kayıtta en az şu alanlar kullanışlıdır:
| Alan | Amaç |
|---|---|
TokenHash |
Açık tokenı veritabanında tutmamak |
SessionId |
Tek cihaz/oturum iptali |
FamilyId |
Rotation zincirini topluca iptal etmek |
ReplacedByTokenHash |
Eski-yeni ilişkisinin denetimi |
ExpiresAt |
Mutlak sona erme |
RevokedAt |
Kullanıldı veya manuel iptal edildi bilgisi |
TokenVersion |
Rol/parola değişiminde eski oturumları geçersiz kılmak |
Refresh token nerede saklanır?
Tarayıcı tabanlı uygulamada XSS ile okunabilen localStorage içine uzun ömürlü token
koymak riski büyütür. Güvenli web uygulamalarında tokenların güvenilen backend tarafında
tutulduğu BFF/cookie yaklaşımı değerlendirilebilir. Cookie kullanılacaksa HttpOnly,
Secure, uygun SameSite, dar Path ve CSRF koruması birlikte tasarlanmalıdır.
Mobil/desktop istemcide işletim sisteminin güvenli credential deposu tercih edilir. Log, exception, analytics payload, URL query string veya ekran görüntüsüne token yazılmaz.
Logout ve revocation
Logout yalnız istemcide token silmek değildir. Sunucu ilgili session veya refresh tokenı iptal etmelidir. Parola değişimi, hesap kapatma, iki faktör değişimi veya kritik güvenlik olayı tüm sessionları ya da ilgili token familylerini iptal edebilir.
Access token stateless ise logout sonrası kısa bir süre geçerli kalabilir. Bu risk kısa expiry, token version/session doğrulaması veya gerekli sistemlerde deny-list ile yönetilir.
Süre nasıl belirlenir?
Evrensel “access token 15 dakika, refresh token 30 gün” kuralı yoktur. Süre; veri hassasiyeti, cihaz türü, tekrar giriş maliyeti, saldırı modeli ve session iptal kapasitesine göre belirlenir. “Beni hatırla” seçeneği daha uzun süre veriyorsa bunu ayrı politika olarak kaydet; sonsuz refresh token üretme.
Hata sözleşmesi
| Durum | Beklenen davranış |
|---|---|
| Token boş veya hash kaydı yok | 401; ayrıntılı iç bilgi sızdırma |
| Token süresi dolmuş | Aileyi gerektiği kadar iptal et, 401 |
| İptal edilmiş token tekrar kullanıldı | Aileyi iptal et, kritik güvenlik olayı yaz, 401 |
| Kullanıcı pasif / token version eski | Oturumu iptal et, 401 |
| Geçerli rotation | Yeni access ve refresh token dön |
| Yetki var fakat kaynak izni yok | 403; refresh ile karıştırma |
Doğrulama senaryoları
- Aynı refresh token art arda iki kez kullanıldığında ikinci istek reddedilir.
- Paralel iki yenilemeden yalnız biri başarılı olur.
- Eski token tekrar kullanıldığında yeni family üyesi de iptal edilir.
- Parola veya token version değişiminden sonra eski session yenilenemez.
- Pasif kullanıcı refresh token ile access token alamaz.
- Veritabanı ve uygulama loglarında açık refresh token bulunmaz.
- Logout sonrası aynı token yenilenemez.
İlgili rehberler
- JWT, Refresh Token ve Oturum Güvenliği
- JWT Oturum İptali, Refresh Rotation ve Token Ailesi
- ASP.NET Core Web API Üretim Klasörleme Standardı