NODE.JS JWT AUTHENTICATION KURMAK

JWT (JSON Web Token) stateless token tabanlı kimlik doğrulama yöntemidir; bu yazıda Node.js'te access/refresh token stratejisini, güvenli saklamayı, iptal ve rotation yöntemlerini kurulum adımlarıyla öğreneceksiniz.
1. JWT nedir?
JSON Web Token; üç parçadan oluşan kodlanmış string:
header.payload.signatureÖrnek:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIxMjM0In0.aBcDeFgHiJÜç parça
- Header: Algoritma ve token tipi (HS256, RS256 vs)
- Payload: Kullanıcı bilgisi (user_id, email, role)
- Signature: Header + payload'ın secret key ile imzalı hash'i
Header ve payload Base64-encoded; herkes okuyabilir. Signature ise secret key gerektirir; sahte token üretmek imkansız. crypto modülü ve güvenli secret üretimi gibi konularda resmi Node.js dokümantasyonu ayrıntılı örnekler sunar.
2. JWT vs Session
| Özellik | JWT | Session |
|---|---|---|
| State | Stateless (sunucuda saklanmaz) | Stateful (sunucuda saklanır) |
| Ölçeklenebilirlik | Çok yüksek | Sticky session gerekir |
| Revocation | Karmaşık | Kolay (DB'den sil) |
| Boyut | Büyük (~500 byte) | Küçük (session ID) |
| Mobil uyum | Mükemmel | Zor |
3. Node.js JWT kurulumu
jsonwebtoken paketi en yaygın:
npm install jsonwebtoken bcryptToken üretme (login)
const jwt = require('jsonwebtoken');
const bcrypt = require('bcrypt');
async function login(req, res) {
const { email, password } = req.body;
// 1. Kullanıcıyı bul
const user = await db.users.findOne({ email });
if (!user) {
return res.status(401).json({ error: 'Geçersiz bilgiler' });
}
// 2. Şifre kontrol
const validPassword = await bcrypt.compare(password, user.password);
if (!validPassword) {
return res.status(401).json({ error: 'Geçersiz bilgiler' });
}
// 3. Token üret
const token = jwt.sign(
{ userId: user.id, role: user.role },
process.env.JWT_SECRET,
{ expiresIn: '1h' }
);
res.json({ token });
}Token doğrulama (middleware)
function authenticate(req, res, next) {
const token = req.headers.authorization?.split(' ')[1];
if (!token) {
return res.status(401).json({ error: 'Token gerekli' });
}
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.user = decoded;
next();
} catch (error) {
if (error.name === 'TokenExpiredError') {
return res.status(401).json({ error: 'Token süresi doldu' });
}
res.status(403).json({ error: 'Geçersiz token' });
}
}
// Kullanım
app.get('/api/profile', authenticate, (req, res) => {
res.json({ userId: req.user.userId });
});4. Access ve Refresh Token stratejisi
Tek token modeli güvenlik sorunu yaratır: token uzun süreli olursa çalınma riski; kısa süreli olursa kullanıcı sürekli login. Çözüm: iki token.
- Access token: Kısa süreli (15 dakika); API çağrılarında kullanılır
- Refresh token: Uzun süreli (7-30 gün); yeni access token almak için kullanılır
Login response
const accessToken = jwt.sign(
{ userId: user.id },
process.env.JWT_ACCESS_SECRET,
{ expiresIn: '15m' }
);
const refreshToken = jwt.sign(
{ userId: user.id },
process.env.JWT_REFRESH_SECRET,
{ expiresIn: '7d' }
);
// Refresh token'ı DB'ye kaydet (revocation için)
await db.refreshTokens.insert({ token: refreshToken, userId: user.id });
res.json({ accessToken, refreshToken });Refresh endpoint
app.post('/api/refresh', async (req, res) => {
const { refreshToken } = req.body;
// 1. DB'de var mı kontrol
const stored = await db.refreshTokens.findOne({ token: refreshToken });
if (!stored) {
return res.status(403).json({ error: 'Geçersiz refresh token' });
}
// 2. Token doğrula
try {
const decoded = jwt.verify(refreshToken, process.env.JWT_REFRESH_SECRET);
// 3. Yeni access token üret
const newAccessToken = jwt.sign(
{ userId: decoded.userId },
process.env.JWT_ACCESS_SECRET,
{ expiresIn: '15m' }
);
res.json({ accessToken: newAccessToken });
} catch (error) {
res.status(403).json({ error: 'Refresh token süresi doldu' });
}
});
5. Güvenli saklama
Frontend (browser)
Üç seçenek var:
- localStorage: Kolay ama XSS saldırılarına açık
- sessionStorage: Tab kapanınca silinir; XSS riski hâlâ var
- httpOnly cookie: En güvenli; JavaScript erişemez
Modern öneri: access token in-memory (state), refresh token httpOnly secure cookie.
Cookie ile saklama
res.cookie('refreshToken', refreshToken, {
httpOnly: true, // JavaScript erişemez
secure: true, // Sadece HTTPS
sameSite: 'strict', // CSRF koruması
maxAge: 7 * 24 * 60 * 60 * 1000 // 7 gün
});6. Token revocation (iptal)
JWT'nin en zor problemi; token üretildikten sonra expire olana kadar geçerli. İptal etmek için:
Refresh token blacklist
Logout veya güvenlik sebebiyle iptal edilen refresh token'ları DB'de "iptal" olarak işaretle. Refresh endpoint'i kontrol etsin.
app.post('/api/logout', async (req, res) => {
const { refreshToken } = req.body;
await db.refreshTokens.deleteOne({ token: refreshToken });
res.json({ message: 'Çıkış yapıldı' });
});Access token kısa süreli
Kısa süreli access token 15 dakikalık olursa iptal etme ihtiyacı pratik olarak azalır; en kötü 15 dakika sonra geçersiz.
Token blacklist (extreme durumlar için)
Acil iptal gerekiyorsa Redis'te blacklist tutulur. Her istekte token blacklist'te mi kontrol edilir.
const redis = require('redis');
const client = redis.createClient();
async function checkBlacklist(req, res, next) {
const token = req.headers.authorization?.split(' ')[1];
const isBlacklisted = await client.get(`blacklist:${token}`);
if (isBlacklisted) {
return res.status(403).json({ error: 'Token iptal edildi' });
}
next();
}7. Payload tasarımı
JWT payload'a ne konulmalı?
Konulmalı
- userId
- role (admin, user)
- iat (issued at, otomatik)
- exp (expiration, otomatik)
Konulmamalı
- Şifre (asla)
- Kart bilgisi
- Çok fazla kişisel veri (token boyutunu büyütür)
- Sık değişen veri (token'da güncel olmaz)
JWT payload herkes tarafından okunabilir (Base64 decode); hassas bilgi koymak ciddi güvenlik riskidir.
8. HS256 vs RS256
| HS256 | RS256 | |
|---|---|---|
| Algoritma | Symmetric (HMAC) | Asymmetric (RSA) |
| Key | Tek secret key | Public/private key çifti |
| Üretme | Secret ile | Private key ile |
| Doğrulama | Aynı secret ile | Public key ile |
| Kullanım | Monolith | Microservices |
Tek bir sunucu için HS256 yeterli; mikroservis mimaride asimetrik RS256 daha uygun (token üreten ve doğrulayan farklı servisler).
9. Yaygın güvenlik hataları
- Zayıf secret key. "123456" yerine cryptographic random (32+ karakter)
- Secret'i hardcoded yazmak. .env dosyasında tut
- localStorage'da token saklamak. XSS riski; httpOnly cookie tercih edilmeli
- HTTPS olmadan kullanmak. Token açıkta gider; ortadaki adam saldırıları
- Token'da hassas veri. Payload base64; herkes okur
- Çok uzun expiration. 1 yıllık token = 1 yıllık güvenlik açığı
- Refresh token rotation yapmamak. Her kullanımda yeni refresh token üret; eskisi iptal
10. Refresh token rotation
İleri güvenlik pratiği; her refresh işleminde hem access hem refresh token yeniden üretilir:
app.post('/api/refresh', async (req, res) => {
const { refreshToken: oldToken } = req.body;
// Eski token'ı doğrula
const decoded = jwt.verify(oldToken, process.env.JWT_REFRESH_SECRET);
// Eski token'ı invalidate et
await db.refreshTokens.deleteOne({ token: oldToken });
// Yeni token çifti üret
const newAccess = jwt.sign({ userId: decoded.userId }, ACCESS_SECRET, { expiresIn: '15m' });
const newRefresh = jwt.sign({ userId: decoded.userId }, REFRESH_SECRET, { expiresIn: '7d' });
await db.refreshTokens.insert({ token: newRefresh, userId: decoded.userId });
res.json({ accessToken: newAccess, refreshToken: newRefresh });
});Çalınmış token tespit edildiğinde tüm zincir invalidate edilebilir.

11. Sürdürme Yolu
JWT authentication modern API geliştirmenin temelidir. Daha kapsamlı bir pratik için kapsamlı Node.js eğitimi authentication ve güvenli API tasarımı konularını birlikte aktarır.
12. Yapının Özeti
JWT authentication stateless token tabanlı modern kimlik doğrulama. jsonwebtoken paketi ile kolay kurulum; access (kısa) + refresh (uzun) token stratejisi standart. Frontend'de httpOnly cookie tercih edilir; localStorage XSS risklidir. Refresh token rotation ile çalınmış token tespiti mümkün. Payload'a hassas veri konulmaz; secret key güçlü ve .env dosyasında. HTTPS olmadan asla kullanılmaz.
Sıkça Sorulan Sorular
JWT mi session-based authentication mı daha iyi?
Bağlıdır. Mikroservis veya ölçeklenebilir API için JWT (stateless); monolith ve <strong>anlık iptal</strong> kritik uygulamalar için session daha kolay. JWT mobil uygulamalar için mükemmel; cookie ile çalışmak zor. Session basit web uygulamalarında daha güvenli; DB'den anlık iptal mümkün. Modern projelerin çoğu JWT tercih ediyor.
Access token süresi ne olmalı?
15 dakika ideal; çoğu API için bu standart. Kısa süre güvenlik için kritik; çalınmış token kısa sürede expire olur. Daha uzun süreler (1 saat+) kullanıcı deneyimi açısından rahat ama güvenlik açığı yaratır. Refresh token ile birlikte 15 dakikalık access kullanıcıyı rahatsız etmez.
localStorage'da token saklamak güvenli mi?
Genelde değil. JavaScript erişimine açık; XSS saldırısı yaparsa saldırgan token'ı çalar. httpOnly cookie ise JavaScript'in erişemediği yer; çok daha güvenli. Modern öneri: access token in-memory state'te (React state, Vuex store); <strong>refresh token</strong> httpOnly secure cookie'de. localStorage sadece düşük güvenlik gerektiren senaryolarda.
JWT secret key ne kadar güçlü olmalı?
Minimum 32 karakter cryptographic random. Örnek üretim: 'crypto.randomBytes(32).toString('hex')' Node.js'te. Asla anlamlı kelime, doğum tarihi veya basit pattern olmamalı. .env dosyasında saklanmalı; koda hardcode edilmemeli. Birden fazla ortam (dev, staging, prod) için ayrı secret'lar kullanılmalı.
Refresh token rotation gerekli mi?
Yüksek güvenlik gerektiren uygulamalar için evet. Bankacılık, sağlık, kurumsal uygulamalarda standart. Sıradan e-ticaret veya blog için aşırı olabilir; <strong>basit refresh akışı</strong> yeterli. Rotation çalınmış refresh token tespiti için kritik; her kullanımda eski silinir, yeni üretilir.
Token blacklist nasıl kurulur?
Redis ile en pratik. Logout veya güvenlik durumunda token'ı Redis'e ekler (expire süresi token'ın kalan süresi kadar). Her authenticate isteğinde token <strong>blacklist'te mi</strong> kontrol edilir. Redis hızlı (mikrosaniye); request yükü çok az. DB'de tutmak da mümkün ama daha yavaş; Redis tercih edilir.
HTTPS olmadan JWT kullanılır mı?
Asla. <strong>JWT token</strong> network üzerinden açık metin olarak gider; ortadaki adam (man-in-the-middle) saldırısıyla çalınır. Production'da HTTPS şart; Let's Encrypt ile ücretsiz SSL sertifikası alınır. Development'ta localhost için exception kabul edilir ama gerçek IP veya domain ile test sırasında HTTPS olmalı.


