diff --git a/pitch-deck/lib/auth.ts b/pitch-deck/lib/auth.ts index 79e0edb..97560cb 100644 --- a/pitch-deck/lib/auth.ts +++ b/pitch-deck/lib/auth.ts @@ -1,4 +1,4 @@ -import { SignJWT, jwtVerify } from 'jose' +import { SignJWT, jwtVerify, decodeJwt } from 'jose' import { randomBytes, createHash } from 'crypto' import { cookies } from 'next/headers' import pool from './db' @@ -125,7 +125,34 @@ export async function getSessionFromCookie(): Promise { const cookieStore = await cookies() const token = cookieStore.get(COOKIE_NAME)?.value if (!token) return null - return verifyJwt(token) + + // Fast path: valid non-expired JWT + const payload = await verifyJwt(token) + if (payload) return payload + + // Slow path: JWT may be expired but DB session could still be valid. + // Decode without signature/expiry check to recover sessionId + sub. + try { + const decoded = decodeJwt(token) as Partial + if (!decoded.sessionId || !decoded.sub) return null + + const valid = await validateSession(decoded.sessionId, decoded.sub) + if (!valid) return null + + // DB session still live — fetch email and reissue a fresh JWT + const { rows } = await pool.query( + `SELECT email FROM pitch_investors WHERE id = $1`, + [decoded.sub] + ) + if (rows.length === 0) return null + + const freshJwt = await createJwt({ sub: decoded.sub, email: rows[0].email, sessionId: decoded.sessionId }) + await setSessionCookie(freshJwt) + + return { sub: decoded.sub, email: rows[0].email, sessionId: decoded.sessionId } + } catch { + return null + } } export function getClientIp(request: Request): string | null {