import { SignJWT, jwtVerify } from 'jose'; import { cookies } from 'next/headers'; const PORTAL_SECRET = new TextEncoder().encode(process.env.BETTER_AUTH_SECRET); export const PORTAL_COOKIE = 'portal_session'; // BREAKING CHANGE (intentional): tokens issued before this change lack aud/iss // and will be rejected by verifyPortalToken. Portal tokens are 24h-lived so // existing sessions will be invalidated on deploy. Users simply re-login. const PORTAL_AUD = 'portal'; const PORTAL_ISS = 'pn-crm'; export interface PortalSession { clientId: string; portId: string; email: string; } export async function createPortalToken(session: PortalSession): Promise { return new SignJWT(session as unknown as Record) .setProtectedHeader({ alg: 'HS256' }) .setAudience(PORTAL_AUD) .setIssuer(PORTAL_ISS) .setExpirationTime('24h') .setIssuedAt() .sign(PORTAL_SECRET); } export async function verifyPortalToken(token: string): Promise { try { const { payload } = await jwtVerify(token, PORTAL_SECRET, { audience: PORTAL_AUD, issuer: PORTAL_ISS, }); return payload as unknown as PortalSession; } catch { return null; } } export async function getPortalSession(): Promise { const cookieStore = await cookies(); const token = cookieStore.get(PORTAL_COOKIE)?.value; if (!token) return null; return verifyPortalToken(token); }