import { generateAndroidAccessToken, getUserById, revokeRefreshSession, rotateRefreshSession } from '../../utils/auth.js' import { assertRateLimit, getClientIp, registerRateLimitFailure, registerRateLimitSuccess } from '../../utils/rate-limit.js' import { writeAuditLog } from '../../utils/audit-log.js' export default defineEventHandler(async (event) => { const ip = getClientIp(event) const body = await readBody(event) const refreshToken = body?.refreshToken if (!refreshToken) { throw createError({ statusCode: 400, message: 'Refresh-Token fehlt' }) } assertRateLimit(event, { name: 'auth:refresh:ip', keyParts: [ip], windowMs: 10 * 60 * 1000, maxAttempts: 60, lockoutMs: 15 * 60 * 1000 }) const rotated = await rotateRefreshSession(refreshToken) if (rotated.status !== 'rotated') { await registerRateLimitFailure(event, { name: 'auth:refresh:ip', keyParts: [ip], delayBaseMs: 100 }) await writeAuditLog('auth.refresh.failed', { ip, reason: rotated.status }) throw createError({ statusCode: 401, message: 'Sitzung ist nicht mehr gültig' }) } const user = await getUserById(rotated.session.userId) if (!user || user.active === false) { await revokeRefreshSession(rotated.refreshToken, 'inactive_or_missing_user') await writeAuditLog('auth.refresh.failed', { ip, userId: rotated.session.userId, reason: 'inactive_or_missing_user' }) throw createError({ statusCode: 401, message: 'Sitzung ist nicht mehr gültig' }) } const accessToken = generateAndroidAccessToken(user, rotated.session.id) registerRateLimitSuccess(event, { name: 'auth:refresh:ip', keyParts: [ip] }) await writeAuditLog('auth.refresh.success', { ip, userId: user.id, sessionId: rotated.session.id }) return { success: true, token: accessToken, accessToken, refreshToken: rotated.refreshToken, sessionId: rotated.session.id } })