182 lines
5.5 KiB
JavaScript
182 lines
5.5 KiB
JavaScript
// routes/auth.js
|
||
const express = require("express")
|
||
const router = express.Router()
|
||
|
||
const requireAuth = require("../middleware/requireAuth.js")
|
||
const { validate } = require("../middleware/validate.middleware")
|
||
const authService = require("../services/auth.service")
|
||
const { endpoints } = require("@shared/contracts")
|
||
|
||
const { mapLoginRequestToLoginInput, mapLoginResultToResponse } = require("../adapters/responses/login.adapter")
|
||
const { mapRegisterRequestToRegisterInput, mapRegisterResultToResponse } = require("../adapters/responses/register.adapter")
|
||
const { mapMeRequestToUserId, mapMeResultToResponse } = require("../adapters/responses/me.adapter")
|
||
|
||
const { auth } = endpoints
|
||
|
||
// NOT: app.js’de cookie-parser olmali:
|
||
// const cookieParser = require("cookie-parser")
|
||
// app.use(cookieParser())
|
||
|
||
function getCookieOptions() {
|
||
const isProd = process.env.NODE_ENV === "production"
|
||
return {
|
||
httpOnly: true,
|
||
secure: isProd,
|
||
sameSite: "lax",
|
||
path: "/",
|
||
}
|
||
}
|
||
|
||
function parseExpiresInToMs(value) {
|
||
if (!value) return 15 * 60 * 1000
|
||
if (typeof value === "number" && Number.isFinite(value)) return value * 1000
|
||
const str = String(value).trim().toLowerCase()
|
||
const match = str.match(/^(\d+)(ms|s|m|h|d)?$/)
|
||
if (!match) return 15 * 60 * 1000
|
||
const n = Number(match[1])
|
||
const unit = match[2] || "s"
|
||
const mult =
|
||
unit === "ms" ? 1 :
|
||
unit === "s" ? 1000 :
|
||
unit === "m" ? 60 * 1000 :
|
||
unit === "h" ? 60 * 60 * 1000 :
|
||
unit === "d" ? 24 * 60 * 60 * 1000 :
|
||
1000
|
||
return n * mult
|
||
}
|
||
|
||
function setRefreshCookie(res, refreshToken) {
|
||
const opts = getCookieOptions()
|
||
const maxAgeMs = Number(process.env.REFRESH_COOKIE_MAX_AGE_MS || 1000 * 60 * 60 * 24 * 30)
|
||
res.cookie("rt", refreshToken, { ...opts, maxAge: maxAgeMs })
|
||
}
|
||
|
||
function setAccessCookie(res, accessToken) {
|
||
const opts = getCookieOptions()
|
||
const maxAgeMs = parseExpiresInToMs(process.env.ACCESS_TOKEN_EXPIRES_IN || "15m")
|
||
res.cookie("at", accessToken, { ...opts, maxAge: maxAgeMs })
|
||
}
|
||
|
||
function clearRefreshCookie(res) {
|
||
const opts = getCookieOptions()
|
||
res.clearCookie("rt", { ...opts })
|
||
}
|
||
|
||
function clearAccessCookie(res) {
|
||
const opts = getCookieOptions()
|
||
res.clearCookie("at", { ...opts })
|
||
}
|
||
|
||
router.post(
|
||
"/register",
|
||
validate(auth.registerRequestSchema, "body", "validatedRegisterInput"),
|
||
async (req, res) => {
|
||
try {
|
||
const input = mapRegisterRequestToRegisterInput(req.validatedRegisterInput)
|
||
|
||
const result = await authService.register({
|
||
...input,
|
||
meta: { ip: req.ip, userAgent: req.headers["user-agent"] || null },
|
||
})
|
||
|
||
// refresh + access cookie set
|
||
if (result.refreshToken) setRefreshCookie(res, result.refreshToken)
|
||
if (result.accessToken) setAccessCookie(res, result.accessToken)
|
||
|
||
const response = auth.authResponseSchema.parse(mapRegisterResultToResponse(result))
|
||
res.json(response)
|
||
} catch (err) {
|
||
const status = err.statusCode || 500
|
||
res.status(status).json({ message: err.message || "Kayit islemi basarisiz." })
|
||
}
|
||
}
|
||
)
|
||
|
||
router.post(
|
||
"/login",
|
||
validate(auth.loginRequestSchema, "body", "validatedLoginInput"),
|
||
async (req, res) => {
|
||
try {
|
||
const input = mapLoginRequestToLoginInput(req.validatedLoginInput)
|
||
|
||
const result = await authService.login({
|
||
...input,
|
||
meta: { ip: req.ip, userAgent: req.headers["user-agent"] || null },
|
||
})
|
||
|
||
// refresh + access cookie set
|
||
setRefreshCookie(res, result.refreshToken)
|
||
setAccessCookie(res, result.accessToken)
|
||
|
||
const response = auth.authResponseSchema.parse(mapLoginResultToResponse(result))
|
||
res.json(response)
|
||
} catch (err) {
|
||
const status = err.statusCode || 500
|
||
res.status(status).json({
|
||
message: err.statusCode ? err.message : "Giris islemi basarisiz.",
|
||
})
|
||
}
|
||
}
|
||
)
|
||
|
||
router.post("/refresh", async (req, res) => {
|
||
try {
|
||
const refreshToken = req.cookies?.rt
|
||
if (!refreshToken) return res.status(401).json({ message: "Refresh token yok" })
|
||
|
||
const result = await authService.refresh({
|
||
refreshToken,
|
||
meta: { ip: req.ip, userAgent: req.headers["user-agent"] || null },
|
||
})
|
||
|
||
// rotate -> yeni refresh + access cookie
|
||
setRefreshCookie(res, result.refreshToken)
|
||
setAccessCookie(res, result.accessToken)
|
||
|
||
const response = auth.authResponseSchema.parse(mapLoginResultToResponse(result))
|
||
res.json(response)
|
||
} catch (err) {
|
||
clearRefreshCookie(res)
|
||
clearAccessCookie(res)
|
||
const status = err.statusCode || 401
|
||
res.status(status).json({ message: err.message || "Refresh basarisiz" })
|
||
}
|
||
})
|
||
|
||
router.post("/logout", async (req, res) => {
|
||
try {
|
||
const refreshToken = req.cookies?.rt
|
||
|
||
if (refreshToken) {
|
||
await authService.logout({
|
||
refreshToken,
|
||
meta: { ip: req.ip, userAgent: req.headers["user-agent"] || null },
|
||
})
|
||
}
|
||
|
||
clearRefreshCookie(res)
|
||
clearAccessCookie(res)
|
||
res.status(204).send()
|
||
} catch (err) {
|
||
clearRefreshCookie(res)
|
||
clearAccessCookie(res)
|
||
const status = err.statusCode || 500
|
||
res.status(status).json({ message: err.message || "Cikis basarisiz" })
|
||
}
|
||
})
|
||
|
||
router.get("/me", requireAuth, async (req, res) => {
|
||
try {
|
||
const userId = mapMeRequestToUserId(req)
|
||
const user = await authService.getMe(userId)
|
||
const response = auth.meResponseSchema.parse(mapMeResultToResponse(user))
|
||
res.json(response)
|
||
} catch (err) {
|
||
const status = err.statusCode || 500
|
||
res.status(status).json({ message: err.message || "Sunucu hatasi" })
|
||
}
|
||
})
|
||
|
||
module.exports = router
|
||
|