import { SignJWT, jwtVerify } from 'jose' import { cookies } from 'next/headers' export type Role = 'admin' | 'user' export interface SessionPayload { userId: string username: string role: Role } export const SESSION_COOKIE = 'backerup_session' const SESSION_DURATION_MS = 7 * 24 * 60 * 60 * 1000 // 7 days // Dev fallback — NOT safe for production (use AUTH_SECRET env var) const DEV_FALLBACK_SECRET = 'dev-secret-NOT-for-production-change-me-32chars!!' export function getSecretKey(): Uint8Array { const secret = process.env.AUTH_SECRET if (!secret) { if (process.env.NODE_ENV !== 'production') { return new TextEncoder().encode(DEV_FALLBACK_SECRET) } throw new Error('AUTH_SECRET environment variable is required in production') } if (secret.length < 32) { throw new Error('AUTH_SECRET must be at least 32 characters long') } return new TextEncoder().encode(secret) } /** Creates and stores a session JWT in an httpOnly cookie. */ export async function createSession(payload: SessionPayload, secure?: boolean): Promise { const expiresAt = new Date(Date.now() + SESSION_DURATION_MS) const token = await new SignJWT({ ...payload }) .setProtectedHeader({ alg: 'HS256' }) .setIssuedAt() .setExpirationTime(expiresAt) .sign(getSecretKey()) // If the caller explicitly passes a value, honour it. // Otherwise fall back to NODE_ENV (safe default for fully-HTTPS deploys). const isSecure = secure !== undefined ? secure : process.env.NODE_ENV === 'production' const cookieStore = await cookies() cookieStore.set(SESSION_COOKIE, token, { httpOnly: true, secure: isSecure, sameSite: 'lax', expires: expiresAt, path: '/', }) } /** Reads and validates the current session cookie. Returns null if missing/invalid. */ export async function getSession(): Promise { const cookieStore = await cookies() const token = cookieStore.get(SESSION_COOKIE)?.value if (!token) return null return verifyToken(token) } /** Deletes the session cookie. */ export async function deleteSession(): Promise { const cookieStore = await cookies() cookieStore.delete(SESSION_COOKIE) } /** Verifies a JWT token string. Edge-runtime safe (uses jose). */ export async function verifyToken(token: string): Promise { try { const { payload } = await jwtVerify(token, getSecretKey(), { algorithms: ['HS256'] }) return { userId: payload.userId as string, username: payload.username as string, role: payload.role as Role, } } catch { return null } }