JWT tabanlı auth akışı, rol bazlı yetkilendirme ve temel güvenlik middleware'leriyle hazırlanmış, hızlı başlangıç için Express + MongoDB template projesi.
- JWT Auth - Access + refresh token, httpOnly cookie ile taşınır
- Rol Bazlı Yetkilendirme -
checkRolemiddleware'i ileuser/editor/admin - Path Alias -
module-aliasile@/model/user.jsgibi importlar - Güvenlik -
helmet, auth uçlarındaexpress-rate-limit,cookie-parser - Logging -
morganile request logları - Env Doğrulama - Boot anında zorunlu değişkenler kontrol edilir, eksikse sunucu açılmaz
- Postman Koleksiyonu - Hazır istek taslaklarıyla uçtan uca test
node-express-template/
├── src/
│ ├── config/
│ │ └── databaseConfig.js # Mongo bağlantısı
│ ├── controller/
│ │ └── authController.js # register, login, logout, tokenRefresh
│ ├── middlewares/
│ │ ├── authMiddleware.js # verifyAccessToken, verifyRefreshToken
│ │ ├── checkRole.js # rol bazlı yetkilendirme
│ │ └── rateLimiter.js # authLimiter
│ ├── model/
│ │ ├── user.js
│ │ └── token.js # refresh token kayıtları
│ ├── routes/
│ │ ├── authRoute.js
│ │ └── testRoute.js # middleware'leri denemek için örnek uçlar
│ ├── utils/
│ │ ├── token.js # generateTokens
│ │ └── validateEnv.js
│ └── server.js # uygulama giriş noktası
├── .env.example
├── .gitignore
├── package.json
├── postman_collection.json
└── README.md
# Bağımlılıkları yükle
npm install
# .env dosyasını oluştur
cp .env.example .env
# Geliştirme sunucusunu başlat (nodemon)
npm run dev
# Production
npm start.env dosyasını doldur:
| Değişken | Açıklama |
|---|---|
PORT |
Sunucunun dinleyeceği port |
MONGO_URI |
MongoDB (Atlas veya local) bağlantı string'i |
ACCESS_TOKEN_SECRET |
Access token imzalama secret'ı |
REFRESH_TOKEN_SECRET |
Refresh token imzalama secret'ı |
Secret üretmek için:
node -e "console.log(require('crypto').randomBytes(64).toString('hex'))"Bu dört değişkenden biri eksikse src/utils/validateEnv.js sunucuyu boot anında durdurur:
const REQUIRED_ENV_VARS = [
"PORT",
"MONGO_URI",
"ACCESS_TOKEN_SECRET",
"REFRESH_TOKEN_SECRET",
];
const validateEnv = () => {
const missing = REQUIRED_ENV_VARS.filter((key) => !process.env[key]);
if (missing.length > 0) {
console.error(
`Eksik ortam değişkenleri: ${missing.join(", ")}. Lütfen .env dosyanızı kontrol edin.`,
);
process.exit(1);
}
};require("module-alias/register");
const dotenv = require("dotenv");
dotenv.config();
const express = require("express");
const helmet = require("helmet");
const morgan = require("morgan");
const cookieParser = require("cookie-parser");
const connectMongoDatabase = require("@/config/databaseConfig.js");
const validateEnv = require("@/utils/validateEnv.js");
validateEnv();
const app = express();
app.use(helmet());
app.use(morgan("dev"));
app.use(express.json());
app.use(cookieParser());
const authRoutes = require("@/routes/authRoute.js");
app.use("/auth", authRoutes);
connectMongoDatabase()
.then(() => {
app.listen(process.env.PORT, () => {
console.log(`Server is running on port ${process.env.PORT}`);
});
})
.catch(() => {
process.exit(1); // DB bağlanamazsa sunucu ayağa kalkmaz
});| Method | Path | Açıklama |
|---|---|---|
| POST | /auth/register |
Yeni kullanıcı oluşturur, cookie'lere token yazar |
| POST | /auth/login |
Giriş yapar, cookie'lere token yazar |
| POST | /auth/logout |
Refresh token'ı DB'den siler, cookie'leri temizler |
| POST | /auth/token-refresh |
Refresh token ile yeni access/refresh token üretir |
register ve login uçları authLimiter ile sınırlıdır (15 dakikada IP başına 20 istek).
const express = require("express");
const router = express.Router();
const {
register,
login,
logout,
tokenRefresh,
} = require("@/controller/authController.js");
const { authLimiter } = require("@/middlewares/rateLimiter.js");
router.post("/register", authLimiter, register);
router.post("/login", authLimiter, login);
router.post("/logout", logout);
router.post("/token-refresh", tokenRefresh);
module.exports = router;const generateTokens = async (user) => {
const accessToken = jwt.sign(
{ userId: user._id, email: user.email, role: user.role },
process.env.ACCESS_TOKEN_SECRET,
{ expiresIn: "15m" },
);
const refreshToken = jwt.sign(
{ userId: user._id },
process.env.REFRESH_TOKEN_SECRET,
{ expiresIn: "7d" },
);
// Kullanıcının eski token kaydını sil, yenisini oluştur
await Token.deleteMany({ userId: user._id });
await Token.create({ userId: user._id, refreshToken, date: new Date() });
return { accessToken, refreshToken };
};Not: Login her seferinde kullanıcının önceki tüm refresh token kayıtlarını siler. Yani aynı kullanıcı ikinci bir cihazdan giriş yaptığında ilk cihazdaki oturum düşer. Çoklu cihaz desteği gerekiyorsa bu mantığın (cihaz başına ayrı token) değiştirilmesi gerekir.
Cookie'den ya da Authorization: Bearer <token> header'ından token'ı okuyup doğrular, geçerliyse req.user'a decode edilmiş payload'ı yazar.
const verifyAccessToken = (req, res, next) => {
const token =
req.cookies.accessToken || req.headers["authorization"]?.split(" ")[1];
if (!token) {
return res.status(401).json({ message: "Access token bulunamadı." });
}
try {
const decoded = jwt.verify(token, process.env.ACCESS_TOKEN_SECRET);
req.user = decoded;
next();
} catch (error) {
return res.status(403).json({ message: "Geçersiz access token." });
}
};req.user.role'ü, izin verilen roller listesiyle karşılaştırır. verifyAccessToken'dan sonra çalıştırılmalı (req.user'ın dolu olması gerekir).
const checkRole = (...roles) => {
return (req, res, next) => {
if (!req.user) {
return res.status(401).json({ message: "Kullanıcı doğrulanamadı." });
}
if (!roles.includes(req.user.role)) {
return res.status(403).json({ message: "Bu işlem için yetkiniz yok." });
}
next();
};
};const { verifyAccessToken } = require("@/middlewares/authMiddleware.js");
const checkRole = require("@/middlewares/checkRole.js");
// Sadece giriş yapmış kullanıcı
router.get("/protected", verifyAccessToken, (req, res) => {
res.json({ user: req.user });
});
// Sadece admin
router.get("/admin-only", verifyAccessToken, checkRole("admin"), (req, res) => {
res.json({ user: req.user });
});Bu middleware'leri denemek için src/routes/testRoute.js altında hazır uçlar var (/test/public, /test/protected, /test/refresh-check, /test/editor-only, /test/admin-only).
Repo kökündeki postman_collection.json dosyasını Postman'e import et. baseUrl değişkeni http://localhost:3005 olarak ayarlı.
Auth > RegisterveyaAuth > Loginisteğini çalıştır (Postman cookie'leri otomatik saklar)Test / Middlewareklasöründeki uçları dene
Yeni kayıt olan kullanıcılar varsayılan olarak role: "user" alır. editor-only / admin-only uçlarını denemek için ilgili kullanıcının role alanını MongoDB'de elle güncellemen gerekir.
Auth dışında yeni bir kaynak (örn. post) eklerken izlenecek sıra:
src/model/post.js— Mongoose şemasısrc/controller/postController.js— CRUD fonksiyonlarısrc/routes/postRoute.js— route tanımları, gerekirseverifyAccessToken/checkRoleile korusrc/server.jsiçine route'u bağla:const postRoutes = require("@/routes/postRoute.js"); app.use("/posts", postRoutes);
- Express 5
- MongoDB / Mongoose
- jsonwebtoken, bcryptjs
- helmet, express-rate-limit, cookie-parser, cors
- morgan
- nodemon (geliştirme)
Not: Bu template proje, JWT tabanlı auth ile hızlı API geliştirme için hazırlanmıştır. İhtiyaca göre özelleştirilebilir (örn. çoklu cihaz oturum desteği, email doğrulama, input validation kütüphanesi eklenmesi).