import { SignJWT, jwtVerify } from 'jose'; import { NextRequest } from 'next/server'; const ALGORITHM = 'HS256'; const TOKEN_EXP_HOURS = 24; function getSecret() { if (!process.env.AUTH_SECRET) { throw new Error('AUTH_SECRET is not set'); } return new TextEncoder().encode(process.env.AUTH_SECRET); } export async function signAccessToken(payload: { userId: string; role: string }) { const secret = getSecret(); const exp = Math.floor(Date.now() / 1000) + TOKEN_EXP_HOURS * 3600; return new SignJWT(payload).setProtectedHeader({ alg: ALGORITHM }).setExpirationTime(exp).sign(secret); } export async function verifyAccessToken(token: string) { const secret = getSecret(); const { payload } = await jwtVerify(token, secret, { algorithms: [ALGORITHM] }); return payload as { userId: string; role: string }; } export async function requireAuth(request: Request | NextRequest) { let token: string | null = null; const header = request.headers.get('authorization'); if (header?.startsWith('Bearer ')) { token = header.slice('Bearer '.length); } if (!token) { const cookieHeader = request.headers.get('cookie') ?? ''; const match = cookieHeader.split(';').map((c) => c.trim()).find((c) => c.startsWith('session_token=')); if (match) { token = decodeURIComponent(match.split('=')[1]); } } if (!token) { throw new Error('Unauthorized'); } return verifyAccessToken(token); } export function buildSessionCookie(token: string) { const secure = process.env.APP_URL?.startsWith('https://') || process.env.NODE_ENV === 'production'; const maxAge = TOKEN_EXP_HOURS * 3600; return `session_token=${encodeURIComponent(token)}; Path=/; HttpOnly; SameSite=Lax; Max-Age=${maxAge};${secure ? ' Secure;' : ''}`; } export function clearSessionCookie() { return 'session_token=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0;'; }