GÜVENLİK9m READ16 Haziran 2026

JWT Nedir, Nasıl Çalışır? Token Authentication Türkçe Anlatım

Header, payload, signature yapısı; access token + refresh token mimarisi ve güvenlik önlemleri.

JWT (JSON Web Token), API'lerde kimlik doğrulama ve yetkilendirme için en yaygın kullanılan standarttır. Bu makale JWT'nin ne olduğunu, nasıl çalıştığını ve doğru nasıl kullanılacağını baştan sona açıklıyor — session tabanlı auth ile karşılaştırmalı olarak.

JWT Nedir?

JWT, RFC 7519 standardıyla tanımlanmış, Base64URL kodlanmış üç parçalı bir token formatıdır:

// PLAINTEXT //
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.eyJ1c2VySWQiOjQyLCJlbWFpbCI6ImFkZW1AZXhhbXBsZS5jb20iLCJyb2xlIjoidXNlciIsImlhdCI6MTc1MDUwMDAwMCwiZXhwIjoxNzUwNTAzNjAwfQ
.Hqm7SKyFxp4FbhLwYq-dEqp8wfCGJ3GEJFjY_LJHiSY
 
Parça 1: Header
Parça 2: Payload
Parça 3: Signature

Header

// JSON //
{
  "alg": "HS256",  // HMAC-SHA256 imza algoritması
  "typ": "JWT"
}

Payload (Claims)

// JSON //
{
  "sub": "42",                    // subject — kullanıcı ID
  "name": "Adem Yılmaz",
  "email": "adem@example.com",
  "role": "admin",
  "iat": 1750500000,              // issued at (Unix timestamp)
  "exp": 1750503600,              // expires (1 saat sonra)
  "iss": "codeforge-api",         // issuer
  "aud": "codeforge-web"          // audience
}

Signature

// PLAINTEXT //
HMACSHA256(
  base64url(header) + "." + base64url(payload),
  SECRET_KEY
)

Sunucu gelen token'ı imzayla doğrular. Payload değiştirilmişse imza uyuşmaz → token geçersiz.

Session vs JWT Karşılaştırması

// PLAINTEXT //
Session Tabanlı:                JWT Tabanlı:
━━━━━━━━━━━━━━━                ━━━━━━━━━━━━
Sunucuda saklanır               Sunucuda saklanmaz (stateless)
Session DB gerekir              DB sorgusu gerekmez
Kolay iptal edilir              İptal için ek mekanizma lazım
Yatay ölçekleme zor             Kolayca ölçeklenir
CSRF risk var                   Cookie değilse CSRF riski az
XSS ile Session ID çalınabilir  XSS ile token çalınabilir

Hangisini seç? SPA ve mobil API → JWT. Geleneksel web uygulaması → Session.

JWT Auth Akışı

// PLAINTEXT //
1. Kullanıcı giriş yapar (POST /auth/login)
   { email, password }
 
2. Sunucu doğrular → JWT üretir
   { accessToken: "eyJ...", expiresIn: 900 }
 
3. Client token'ı saklar ve her istekte gönderir
   Authorization: Bearer eyJ...
 
4. Sunucu token'ı doğrular → isteği işler
   jwt.verify(token, SECRET) → payload
 
5. Token süresi dolarsa → refresh token ile yenile
   POST /auth/refresh → yeni accessToken

Access Token + Refresh Token

Kısa ömürlü access token + uzun ömürlü refresh token kombinasyonu güvenli en yaygın yaklaşımdır:

// PLAINTEXT //
Access Token:  15 dakika ömürlü, Authorization header'da
Refresh Token: 30 gün ömürlü, HttpOnly cookie'de
 
Neden iki token?
• 15 dakika sonra access token expire → refresh token ile yenile
• Refresh token çalınırsa → DB'den sil → anında geçersiz
• Access token çalınırsa → 15 dakika sonra otomatik expire
// JAVASCRIPT //
// Basit implementasyon
const login = async (email, password) => {
  const res = await fetch('/api/auth/login', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    credentials: 'include',   // refresh token cookie için
    body: JSON.stringify({ email, password }),
  });
  const { accessToken } = await res.json();
  // accessToken'ı memory'de sakla (localStorage'da SAKLAMA)
  return accessToken;
};
 
// Her API isteğinde
const getUsers = async (accessToken) => {
  const res = await fetch('/api/users', {
    headers: { Authorization: `Bearer ${accessToken}` },
  });
  return res.json();
};

Nerede Saklamalısın?

// PLAINTEXT //
localStorage:
✗ XSS saldırısına açık — her JavaScript erişebilir
✗ Kötü amaçlı script token'ı çalabilir
✗ ASLA access token saklama
 
sessionStorage:
✗ Tab kapanınca gider
✗ Yine XSS açığı var
✗ Önerilmez
 
HttpOnly Cookie:
✓ JavaScript erişemez → XSS'e karşı güvenli
✓ Tarayıcı otomatik gönderir
✗ CSRF riski → SameSite=Strict ile engelle
✓ Refresh token için ideal
 
Memory (değişkende):
✓ JavaScript'e erişim kontrolü
✓ Tab kapanınca temizlenir
✓ Access token için en güvenli
✗ Sayfa yenilenince kaybolur → refresh gerekir

Yaygın Güvenlik Hataları

// JAVASCRIPT //
// YANLIŞ — zayıf secret
const token = jwt.sign(payload, 'sifre123');
 
// DOĞRU — minimum 256-bit güçlü secret
const token = jwt.sign(payload, process.env.JWT_SECRET);  // 32+ karakter rastgele
 
// YANLIŞ — algoritma doğrulaması yok
jwt.verify(token, secret);
 
// DOĞRU — algorithm belirt
jwt.verify(token, secret, { algorithms: ['HS256'] });
 
// YANLIŞ — payload'da şifre var
const payload = { userId: 1, password: hash };  // asla!
 
// YANLIŞ — exp yok — token sonsuza kadar geçerli
jwt.sign({ userId: 1 }, secret);
 
// DOĞRU — her zaman expiry ekle
jwt.sign({ userId: 1 }, secret, { expiresIn: '15m' });

Token İptal Etme

JWT'nin en büyük dezavantajı: token expire olmadan iptal edilemez. Çözümler:

// JAVASCRIPT //
// 1. Kısa expiry (15dk) — pratik yaklaşım
 
// 2. Token blacklist (Redis)
const revokedTokens = new Set(); // production'da Redis kullan
 
function revokeToken(jti) {
  redis.setex(`revoked:${jti}`, 900, '1');  // 15dk sonra otomatik sil
}
 
async function verifyToken(token) {
  const payload = jwt.verify(token, SECRET);
  const isRevoked = await redis.get(`revoked:${payload.jti}`);
  if (isRevoked) throw new Error('Token revoked');
  return payload;
}
 
// 3. Refresh token DB'de saklama — logout = DB'den sil

Decode vs Verify

// JAVASCRIPT //
const jwt = require('jsonwebtoken');
 
// decode — imzayı DOĞRULAMADAN payload'ı oku
// GÜVENLİ DEĞİL — sadece debug için
const payload = jwt.decode(token);
console.log(payload);  // imzasız okuma
 
// verify — imzayı doğrula, payload döner
try {
  const payload = jwt.verify(token, process.env.JWT_SECRET);
  // payload güvenilir
} catch (err) {
  if (err.name === 'TokenExpiredError') { /* refresh */ }
  if (err.name === 'JsonWebTokenError') { /* geçersiz */ }
}

Özet

JWT üç parçadan oluşur: header (algoritma), payload (kullanıcı bilgisi) ve signature (doğrulama). Access token 15 dakika ömürlü ve Authorization header'da, refresh token 30 gün ömürlü ve HttpOnly cookie'de tutulmalı. localStorage'da token saklamak XSS riski yaratır. Her token'a exp claim ekle, güçlü secret kullan, algoritma belirt. İptal için ya kısa expiry ya Redis blacklist ya da DB tabanlı refresh token yönetimi gerekir.