Foruma hoş geldin 👋, Ziyaretçi

Forum içeriğine ve tüm hizmetlerimize erişim sağlamak için foruma kayıt olmalı ya da giriş yapmalısınız. Foruma üye olmak tamamen ücretsizdir.

JWT token'ları güvenli bir şekilde nasıl saklarım? Refresh token stratejisi oluşturma

codrix

Üye
Katılım
14 Mart 2026
Mesajlar
50
Merhaba arkadaşlar, bugün başımı çok ağrıtan bir konudan bahsedeceğim: JWT token güvenliği. Bir projede, kullanıcı giriş yaptıktan sonra gelen JWT'yi nereye koyacağım konusunda kafayı yemiştim. LocalStorage mı, sessionStorage mı, cookies mi? Hangisi daha güvenli? Üstüne bir de token'ın süresi dolunca kullanıcıyı tekrar login sayfasına atmak istemiyordum. İşte tüm bu dertlere bulduğum, benim için en temiz çözümü anlatacağım.

🔥 Karşılaştığım Büyük İkilem

İlk başta herkes gibi ben de token'ı localStorage'a atmıştım. Çok pratikti ama bir XSS (Cross-Site Scripting) açığı durumunda token'ın çalınabileceğini öğrenince içim rahat etmedi. sessionStorage biraz daha iyiydi ama sekme kapanınca token uçuyordu, kullanıcı deneyimi kötüydü. HTTP-only cookies ise XSS'e karşı daha dayanıklı ama CSRF (Cross-Site Request Forgery) riski taşıyordu. "Yok artık, bu işin içinden nasıl çıkacağım?" dediğim anda araştırmalarım beni Access Token + Refresh Token ikilisine ve HTTP-only cookies'e yöneltti.

🛡️ Benim Tercih Ettiğim Güvenli Mimari

Sonunda oturttuğum sistem şu şekilde:
1. Access Token (JWT): Kısa ömürlü (5-15 dakika). İsteklerin Authorization header'ı ile gönderilir.
2. Refresh Token: Uzun ömürlü (7 gün, 1 ay gibi). Sadece yeni access token almak için kullanılır. MUTLAKA HTTP-only, Secure, SameSite=Strict cookie olarak saklanır.
Bu sayede access token ele geçirilse bile kısa sürede geçersiz hale geliyor. Refresh token ise JavaScript'ten erişilemediği için XSS'ten nispeten korunaklı.

⚙️ Backend Tarafında Refresh Mantığı (Node.js Örneği)

İşte login endpoint'inde ve token refresh işleminde kullandığım temel yapı. Önce kullanıcı giriş yaptığında hem access token hem de refresh token üretip, refresh token'ı cookie'ye koyuyoruz.

JavaScript:
// Kullanıcı Login Olduğunda
app.post('/api/login', async (req, res) => {
  // ... Kullanıcı doğrulama işlemleri ...
  const user = await User.findOne({ email: req.body.email });

  const accessToken = jwt.sign(
    { userId: user._id },
    process.env.ACCESS_TOKEN_SECRET,
    { expiresIn: '15m' }
  );

  const refreshToken = jwt.sign(
    { userId: user._id },
    process.env.REFRESH_TOKEN_SECRET,
    { expiresIn: '7d' }
  );

  // Refresh Token'ı HTTP-only Cookie'ye kaydet
  res.cookie('refreshToken', refreshToken, {
    httpOnly: true,
    secure: process.env.NODE_ENV === 'production', // HTTPS'te çalışıyor
    sameSite: 'strict',
    maxAge: 7  24  60  60  1000 // 7 gün
  });

  // Access Token'ı response body'si ile gönder
  res.json({ accessToken });
});

Şimdi de access token süresi dolduğunda, istemci tarafından özel bir endpoint'e yapılan istekle yeni bir token alalım.

JavaScript:
// Yeni Access Token Alma (Refresh) Endpoint'i
app.post('/api/refresh-token', (req, res) => {
  const refreshToken = req.cookies.refreshToken;

  if (!refreshToken) {
    return res.sendStatus(401); // Unauthorized
  }

  // Cookie'den gelen token geçerli mi?
  jwt.verify(refreshToken, process.env.REFRESH_TOKEN_SECRET, (err, user) => {
    if (err) {
      return res.sendStatus(403); // Forbidden (Token geçersiz/yanlış)
    }

    // Refresh token geçerliyse yeni bir access token üret
    const newAccessToken = jwt.sign(
      { userId: user.userId },
      process.env.ACCESS_TOKEN_SECRET,
      { expiresIn: '15m' }
    );

    res.json({ accessToken: newAccessToken });
  });
});

🌐 Frontend Tarafında İstekleri Yönetmek (Axios Interceptor)

Frontend'de, her istekte token'ı header'a eklemek ve 401 hatası alındığında otomatik olarak yenilemek için Axios Interceptor kullanıyorum. Bu, kullanıcıyı hiç hissettirmeden token'ı tazeler.

JavaScript:
import axios from 'axios';

const api = axios.create({ baseURL: '/api' });

// Her istekten önce token'ı header'a ekle
api.interceptors.request.use(
  (config) => {
    const token = localStorage.getItem('accessToken'); // Access token'ı burada saklıyorum
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }
    return config;
  },
  (error) => Promise.reject(error)
);

// Yanıtları dinle, 401 hatasında token'ı yenile
api.interceptors.response.use(
  (response) => response,
  async (error) => {
    const originalRequest = error.config;
    if (error.response?.status === 401 && !originalRequest._retry) {
      originalRequest._retry = true;
      try {
        // Refresh token endpoint'ine istek yap
        const response = await axios.post('/api/refresh-token', {}, { withCredentials: true });
        const newAccessToken = response.data.accessToken;
        localStorage.setItem('accessToken', newAccessToken);
        // Yeni token ile başarısız olan isteği tekrarla
        originalRequest.headers.Authorization = `Bearer ${newAccessToken}`;
        return api(originalRequest);
      } catch (refreshError) {
        // Refresh token da geçersizse, kullanıcıyı login sayfasına yönlendir
        window.location.href = '/login';
        return Promise.reject(refreshError);
      }
    }
    return Promise.reject(error);
  }
);

✅ Sonuç ve Tavsiyelerim

Bu yapıyı kurduktan sonra hem güvenlik konusunda içim rahat etti hem de kullanıcı deneyimi mükemmel oldu. Kullanıcı, access token'ı süresi dolsa bile arka planda yenilendiği için uygulamadan atılmıyor. Tabii ki mutlak güvenlik diye bir şey yok. Bu yapının yanında sunucu tarafında refresh token'ları bir veritabanında veya Redis'te tutup, iptal etme (logout all devices) özelliği de ekleyebilirsiniz.

Siz JWT token'larınızı nasıl saklıyorsunuz? Bu refresh token stratejisini kullanıyor musunuz? Ya da "Ben refresh token'ı da veritabanında tutuyorum, daha güvenli" diyenler var mı? Fikirlerinizi merakla bekliyorum, aşağıdaki yorumlarda buluşalım!
 

Tema özelleştirme sistemi

Bu menüden forum temasının bazı alanlarını kendinize özel olarak düzenleye bilirsiniz.

Zevkine göre renk kombinasyonunu belirle

Tam ekran yada dar ekran

Temanızın gövde büyüklüğünü sevkiniz, ihtiyacınıza göre dar yada geniş olarak kulana bilirsiniz.

Geri