47 lines
1.4 KiB
TypeScript
47 lines
1.4 KiB
TypeScript
import { SignJWT, jwtVerify } from "jose"
|
|
|
|
// Secreto de firma: JWT_SECRET explícito > WEB_PASSWORD > secreto efímero
|
|
// aleatorio (modo dev sin contraseña — las sesiones no sobreviven restart,
|
|
// pero no hay nada hardcodeado ni predecible en el código).
|
|
// NOTA: usa Web Crypto global (crypto.randomUUID) porque auth.ts corre
|
|
// también en el middleware de Edge Runtime, donde node:crypto NO existe.
|
|
const SECRET = new TextEncoder().encode(
|
|
process.env.JWT_SECRET || process.env.WEB_PASSWORD || `${crypto.randomUUID()}${crypto.randomUUID()}`,
|
|
)
|
|
|
|
const COOKIE_NAME = "session"
|
|
|
|
export interface SessionPayload {
|
|
authenticated: boolean
|
|
timestamp: number
|
|
}
|
|
|
|
export async function createSession(): Promise<string> {
|
|
return new SignJWT({ authenticated: true, timestamp: Date.now() })
|
|
.setProtectedHeader({ alg: "HS256" })
|
|
.setExpirationTime("7d")
|
|
.sign(SECRET)
|
|
}
|
|
|
|
export async function verifySession(token: string): Promise<SessionPayload | null> {
|
|
try {
|
|
const { payload } = await jwtVerify(token, SECRET)
|
|
return payload as unknown as SessionPayload
|
|
} catch {
|
|
return null
|
|
}
|
|
}
|
|
|
|
export function sessionCookieOptions(): { name: string; options: { httpOnly: boolean; secure: boolean; sameSite: "lax"; path: string; maxAge: number } } {
|
|
return {
|
|
name: COOKIE_NAME,
|
|
options: {
|
|
httpOnly: true,
|
|
secure: process.env.NODE_ENV === "production",
|
|
sameSite: "lax",
|
|
path: "/",
|
|
maxAge: 60 * 60 * 24 * 7,
|
|
},
|
|
}
|
|
}
|