diff --git a/src/lib/session.ts b/src/lib/session.ts index 689847c..0f36629 100644 --- a/src/lib/session.ts +++ b/src/lib/session.ts @@ -4,24 +4,32 @@ import { cookies } from "next/headers"; // SESSION_SECRET is REQUIRED. No fallback: a public default would let anyone // forge a 7-day admin JWT if the env var ever fails to load in production. // Generate a strong value with: openssl rand -base64 48 -const secretKey = process.env.SESSION_SECRET; -if (!secretKey || secretKey.length < 32) { - throw new Error( - "SESSION_SECRET environment variable is required (min 32 chars). " + - "Generate one with: openssl rand -base64 48" - ); +// +// Validated LAZILY (inside getEncodedKey, not at module load). `next build` +// imports this module during page-data collection without runtime env vars, +// so a top-level throw would break the build. At runtime, any attempt to +// create a session without a valid secret still throws loudly — the secret +// is never defaulted, so admin JWTs can't be forged. +function getEncodedKey(): Uint8Array { + const secretKey = process.env.SESSION_SECRET; + if (!secretKey || secretKey.length < 32) { + throw new Error( + "SESSION_SECRET environment variable is required (min 32 chars). " + + "Generate one with: openssl rand -base64 48" + ); + } + return new TextEncoder().encode(secretKey); } -const encodedKey = new TextEncoder().encode(secretKey); export async function createSession(userId: string, username: string) { const expiresAt = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000); // 7 días de duración - + // Creamos el token (El "pase de acceso" encriptado) const sessionToken = await new SignJWT({ userId, username }) .setProtectedHeader({ alg: "HS256" }) .setIssuedAt() .setExpirationTime("7d") - .sign(encodedKey); + .sign(getEncodedKey()); // En Next.js 15+, cookies() es una Promesa const cookieStore = await cookies();