import type { JWT } from 'next-auth/jwt' import { encode } from 'next-auth/jwt' const API_BASE = process.env.API_BASE_URL ?? 'http://localhost:8080' /** Access token bitiminden önce yenile (ms) — backend 15 dk ise güvenli tampon */ const REFRESH_BUFFER_MS = 120_000 /** NextAuth JWT şifreli cookie ömrü (saniye) — varsayılan NextAuth ile uyumlu */ const JWT_COOKIE_MAX_AGE_SEC = 30 * 24 * 60 * 60 export function sessionCookieName(): string { return isSecureSessionCookieEnabled() ? '__Secure-next-auth.session-token' : 'next-auth.session-token' } export function getJwtExpMs(accessToken: string): number { try { const payloadPart = accessToken.split('.')[1] if (!payloadPart) return Date.now() const payload = JSON.parse(Buffer.from(payloadPart, 'base64url').toString('utf8')) as { exp?: number } if (!payload.exp) return Date.now() return payload.exp * 1000 } catch { return Date.now() } } /** Access süresi dolmak üzereyse veya dolmuşsa true */ export function shouldRefreshBackendToken(token: JWT | null): boolean { if (!token?.refreshToken) return false const exp = token.accessTokenExpires as number | undefined if (!exp) return true return Date.now() >= exp - REFRESH_BUFFER_MS } export async function fetchRefreshedBackendJwt(token: JWT): Promise { const refreshToken = token.refreshToken if (!refreshToken) return null try { const res = await fetch(`${API_BASE}/api/v1/auth/refresh`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ refresh_token: refreshToken }), }) if (!res.ok) return null const data = (await res.json()) as { access?: unknown; refresh?: unknown } // Backend: { "access": "...", "refresh": "..." } — Login_Register.md ile aynı if (typeof data.access !== 'string' || !data.access) return null const accessToken = data.access const nextRefresh = typeof data.refresh === 'string' && data.refresh.length > 0 ? data.refresh : refreshToken return { ...token, accessToken, refreshToken: nextRefresh, accessTokenExpires: getJwtExpMs(accessToken), error: undefined, } } catch { return null } } export async function encodeSessionJwt(token: JWT): Promise { const secret = process.env.NEXTAUTH_SECRET ?? process.env.AUTH_SECRET if (!secret) throw new Error('NEXTAUTH_SECRET eksik') return encode({ token, secret, maxAge: JWT_COOKIE_MAX_AGE_SEC, }) } export function sessionCookieOptions(): { httpOnly: boolean secure: boolean sameSite: 'lax' path: string maxAge: number } { const secure = isSecureSessionCookieEnabled() return { httpOnly: true, secure, sameSite: 'lax', path: '/', maxAge: JWT_COOKIE_MAX_AGE_SEC, } } export function isSecureSessionCookieEnabled(): boolean { return ( !!process.env.NEXTAUTH_URL?.startsWith('https://') || !!process.env.VERCEL ) } /** Server action / Route Handler: güncellenmiş JWT’yi NextAuth session çerezine yazar */ export function applySessionCookie( cookieStore: { set: (name: string, value: string, options: Record) => void }, jwt: string ): void { cookieStore.set(sessionCookieName(), jwt, sessionCookieOptions()) }