Token tuzağı, tek bir kullanıcı tarafından açılan beş sekmenin aynı milisaniyede süresi dolmuş bir JWT'yi yenilemeye çalışmasıyla canlı bir sitede gerçekleşti; bu durum backend'i mükerrer yenileme istekleriyle doldurdu ve oturumu anında geçersiz kıldı. Her sekme kullanıcıyı oturumdan attı ve bu da token yenileme için tek sekmeli bir çözümün artık yeterli olmadığını kanıtladı.

Token tuzağı neden önemlidir

Modern tek sayfa uygulamaları (SPA), kısa ömürlü erişim token'ları (access tokens) ve uzun ömürlü bir yenileme token'ı (refresh token) kullanır. Erişim token'ının süresi dolduğunda, istemci bir yenileme isteği gönderir, yeni bir token çifti alır ve orijinal çağrıyı tekrar dener. Çoğu geliştirici, bu akışı bellek içi bir bayrakla (örneğin, isRefreshing = true) veya bir istek kuyruğuyla korur ve bunu tek bir sekmede test eder. Gerçek dünyada kullanıcılar birkaç sekmeyi açık tutar: bir ayarlar sayfası, bir analitik paneli ve birkaç veri görünümü. Erişim token'ının süresi dolduğunda, her sekme 401 hatasını bağımsız olarak algılar, her biri bir yenileme isteği başlatır ve backend —özellikle yenileme token'ı rotasyonunu (refresh-token rotation) zorunlu kılıyorsa— ikinci isteği bir yeniden oynatma (replay) olarak algılar ve tüm oturumu iptal eder.

JavaScript izolasyonu soruna yol açar

Her tarayıcı sekmesi kendi JavaScript bağlamını (context) çalıştırır. Değişkenler, zamanlayıcılar ve bellek içi bayraklar, aynı kökene (origin) sahip olsalar bile diğer sekmeler tarafından görülemez. "Bir yenileme zaten devam ediyor" diyen bir bayrak, yalnızca onu ayarlayan sekmenin içinde yaşar. Diğer sekmelerin token'ın başka bir yerde yenilendiğini bilmesinin bir yolu yoktur, bu nedenle hepsi kendi ağ çağrısını başlatır. Sorun interceptor'daki bir hata değil; istemci tarafı durum izolasyonunun (client-side state isolation) temel bir kısıtlamasıdır.

Web Locks API imdada yetişiyor

Bir sekme bir kilidi (lock) tuttuğunda, aynı kilidi isteyen diğer tüm sekmeler kilit serbest bırakılana kadar beklemek zorundadır.

Token yenileme için nasıl çalışır

  1. 401 Hatasını Algıla – Yetkisiz bir yanıt alan herhangi bir sekme navigator.locks.request('auth_token_refresh_lock', async lock => { … }) çağrısı yapar.
  2. Kilidi Edin – Eğer başka bir sekme kilidi tutmuyorsa, mevcut sekme devam eder; aksi takdirde kilit serbest kalana kadar duraklatılır.
  3. Bir Kez Yenile – Kilidi tutan sekme yenileme isteğini gönderir, yeni erişim token'ını ve bir zaman damgasını (timestamp) localStorage içinde saklar ve ardından callback tamamlandığında kilidi otomatik olarak serbest bırakır.
  4. Mükerrer İşlemi Atla – Bekleyen bir sekme sonunda kilidi aldığında, localStorage'dan zaman damgasını okur. Eğer token yapılandırılabilir bir pencere içinde (örneğin son birkaç saniye içinde) yenilenmişse, sekme ağ çağrısını atlar ve bellek içi token'ını localStorage'dan günceller.
  5. Çökmeleri Yönet – Eğer bir sekme kilidi tutarken çökerse veya kapatılırsa, tarayıcı kilidi serbest bırakarak başka bir sekmenin yenilemeyi tekrar denemesine olanak tanır.

Bir bakışta avantajlar

  • Sıfır mükerrer ağ çağrısı – Sadece ilk sekme backend ile iletişim kurar.
  • Oturum sonlanması yaşanmaz – Yenileme token'ı rotasyonu tek bir kullanım görür ve oturumu canlı tutar.
  • Sorunsuz kurtarma – Tarayıcı tarafından yönetilen kilit serbest bırakma, bir sekme kaybolduğunda kilitlenmeleri (deadlocks) önler.

Uygulama kontrol listesi

  • Yenileme mantığını bir kilit isteği ile Axios (veya fetch) interceptor'ınızın içine sarmalayın.
  • Yenilenen token'ı ve bir milisaniye zaman damgasını localStorage içinde (veya oturum bazlı veri tercih ediyorsanız sessionStorage içinde) saklayın.
  • Bir kilit verildiğinde, saklanan zaman damgasını Date.now() ile karşılaştırın. Fark eşik değerinizin altındaysa, backend'i çağırmak yerine token'ı depolamadan okuyun.
  • Interceptor'ın, orijinal API çağrısını tekrar denemeden önce, depolamadan alınan token ile istek başlıklarını (request headers) güncellediğinden emin olun.
  • Akışı birden fazla sekme ile test edin; yalnızca bir yenileme isteğinin sunucuya ulaştığını doğrulamak için ağ gecikmesini (network latency) simüle edin.

Neler ters gidebilir

Bir sonraki adımda nelere dikkat edilmeli

Özet

Her tarayıcı sekmesini küçük bir dağıtık sistemdeki bir düğüm (node) olarak değerlendirin. JWT yenilemelerini sıralı hale getirmek için Web Locks API kullanarak mükerrer çağrıları ortadan kaldırabilir, yenileme token'ı rotasyonunu koruyabilir ve kullanıcıların tüm açık sekmelerinde oturumlarını açık tutabilirsiniz.