Ana içeriğe geç

🎯 Giriş

JWT (JSON Web Token), modern API'lerde en yaygın kullanılan durumsuz (stateless) kimlik doğrulama yöntemidir. Geleneksel session yapıları sunucuda durum saklamayı zorunlu kıldığı için, dağıtık ve mikro servis tabanlı sistemlerde ek yük oluşturur. JWT ise bu durumu ortadan kaldırarak sunucunun durum tutmadan isteği doğrulamasını sağlar.

Bu rehberde Express.js ile uçtan uca JWT tabanlı kimlik doğrulama kuracak, erişim–yenileme token mantığını uygulayacak ve tüm güvenlik aşamalarını öğreneceksiniz.


Bu Rehberde Ne Öğreneceksiniz?

  • JWT yapısı (Header, Payload, Signature)
  • Access & Refresh token mimarisi
  • authenticateToken middleware yazımı
  • HttpOnly cookie ile güvenli refresh token saklama
  • Token yenileme akışı (/auth/refresh)
  • Token versioning ile replay saldırılarını engelleme
  • Rol tabanlı yetkilendirme (RBAC)

1. Express.js Projesini Oluşturma

Proje başlatma

npm init -y

ES Modules açma


"type": "module"

Gerekli paketler


npm install express dotenv jsonwebtoken cookie-parser

Basit proje yapısı


src/
app.js
middleware/
routes/
controllers/
config/

2. Express Başlangıç Dosyası


import express from 'express';
import dotenv from 'dotenv';

// Ortam değişkenlerini yükler
dotenv.config();

const app = express();

// JSON gövdesini ayrıştırır
app.use(express.json());

// Sunucuyu başlatır
app.listen(3000, () => console.log('Sunucu 3000 portunda çalışıyor'));

3. JWT Yapısını Anlamak (GÜÇLENDİRİLMİŞ Bölüm)

JWT üç bölümden oluşur:

BölümAçıklamaÖrnek
HeaderAlgoritma & token türü{ "alg": "HS256", "typ": "JWT" }
PayloadKullanıcı kimliği + claims{ "sub": "123", "role": "user", "exp": 1767215999 }
SignatureHeader + Payload'ın gizli anahtarla imzasıKriptografik hash

✔ Payload şifreli değildir, sadece Base64URL kodludur. ✔ Hassas veri ASLA payload’a eklenmez.


4. Access Token Oluşturma


JWT_SECRET="guclu-gizli-anahtar"

import jwt from "jsonwebtoken";

// Access token üretir (15 dk)
function generateAccessToken(userId, role) {
const payload = { sub: userId, role };
const token = jwt.sign(payload, process.env.JWT_SECRET, {
expiresIn: "15m",
});

return token;
}

✔ Bu token kısa süreli olmalı. ✔ Çalınırsa zararı düşük olur.


5. JWT Doğrulama Middleware’i


import jwt from "jsonwebtoken";

// Korunan rotalar için doğrulama middleware'i
export function authenticateToken(req, res, next) {
const header = req.headers["authorization"];
const token = header?.split(" ")[1]; // Bearer kısmını atla

if (!token)
return res.status(401).json({ message: "Token bulunamadı" });

jwt.verify(token, process.env.JWT_SECRET, (err, decoded) => {
if (err)
return res.status(403).json({ message: "Token geçersiz" });

req.user = decoded;
next();
});
}

✔ Token yok → 401 Unauthorized ✔ Token var ama geçersiz → 403 Forbidden


6. Access Token & Refresh Token Mimarisı

TokenSüreAmaçSaklama
Access15 dkAPI isteklerini doğrulamaBellek / Authorization header
Refresh7 günYeni access token almaHttpOnly + Secure cookie

✔ Refresh token kesinlikle localStorage’a konmaz. ✔ XSS’den korunmak için HttpOnly şarttır.


7. Refresh Token Endpoint (/auth/refresh)


import jwt from "jsonwebtoken";

// HttpOnly cookie okumak için cookie-parser gerekir
export async function refreshTokenHandler(req, res) {
const refresh = req.cookies?.refreshToken;

if (!refresh)
return res.status(401).json({ message: "Refresh token yok" });

// Refresh doğrulama
jwt.verify(refresh, process.env.REFRESH_SECRET, (err, decoded) => {
if (err)
return res.status(403).json({ message: "Refresh token geçersiz" });

// Yeni access token oluştur
const newAccess = jwt.sign(
{ sub: decoded.sub, role: decoded.role },
process.env.JWT_SECRET,
{ expiresIn: "15m" }
);

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

8. Token Versioning & Replay Saldırısı Koruması (GÜÇLENDİRİLMİŞ Bölüm)

Uzun ömürlü refresh token’lar çalınmaya çok uygundur. Bunu engellemenin iki yolu vardır:

1. Token Versioning (En güçlü yöntem)

Veritabanına:


user.tokenVersion = 1

Refresh token içine:


{ "sub": "123", "role": "user", "ver": 1 }

Yenileme geldiğinde:

Token içindeki ver

DB’deki tokenVersion ile karşılaştırılır

Yeni refresh token üretildiğinde version → +1 yapılır

Eski tokenlar otomatik çöp olur

2. Revocation List (İptal Listesi)

Refresh token’a bir UUID verilir. Logout olduğunda bu ID iptal listesine eklenir.

Redis burada en hızlı çözümdür.


9. Rol Bazlı Yetkilendirme (RBAC)


export function adminOnly(req, res, next) {
if (req.user?.role !== "admin") {
return res.status(403).json({ message: "Yetkin yok" });
}
next();
}

Kullanımı:


app.get("/admin/panel", authenticateToken, adminOnly, (req, res) => {
res.json({ message: "Admin paneline hoş geldin!" });
});

10. Güvenlik Önerileri (Güncellenmiş)

Access token → kısa ömürlü

Refresh token → HttpOnly + Secure cookie

Gizli anahtarlar .env içinde

Algoritma olarak HS256 veya RS256 kullan

Payload’a gizli veri koyma

Refresh token için versioning kullan

HTTPS zorunlu olmalı

JWT’yi localStorage’a koyma


11. Sıkça Sorulan Sorular

1. JWT şifreli mi?

Hayır, sadece imzalıdır.

2. Neden iki token var?

Access kısa ömürlü, refresh uzun ömürlüdür. Dengeli güvenlik sağlar.

3. Refresh token nerede saklanır?

HttpOnly + Secure cookie.

4. Süresi dolmuş token nasıl anlaşılır?

jwt.verify otomatik hata döndürür.


✔ Sonuç

Bu entegre rehber, Google sıralamasında daha güçlü olabilir çünkü:

Bölüm geçişleri güçlendirildi

Token versioning detaylandırıldı

JWT yapısı tablo halinde açıklandı

Rabisu Bulut üzerinde Node.js projelerini direkt test edebilir ve dağıtabilirsiniz. 🚀🔥