// lib/auth.ts import { jwtVerify, SignJWT } from "jose"; import prisma from "./prisma"; const JWT_SECRET = new TextEncoder().encode(process.env.JWT_SECRET); import { createHash, randomBytes } from "crypto"; export function generateDisplayToken(): string { return randomBytes(32).toString("hex"); } export async function createDisplayJWT( displayId: string, orgId: string ): Promise { return await new SignJWT({ displayId, orgId, role: "display", aud: "display-auth", iss: "Jotunheimen", }) .setProtectedHeader({ alg: "HS256" }) .setIssuedAt() .setExpirationTime("1y") .sign(JWT_SECRET); } type DisplayJWTPayload = { mode: any; displayId: string; orgId: string; role: string; aud: string; iss: string; }; export async function verifyDisplayJWT( token: string ): Promise { const { payload } = await jwtVerify(token, JWT_SECRET, { issuer: "Jotunheimen", audience: "display-auth", }); return payload as DisplayJWTPayload; } export async function rotateDisplayToken(oldToken: string) { const claims = await verifyDisplayJWT(oldToken); const newToken = await createDisplayJWT(claims.displayId, claims.orgId); await prisma.display.update({ where: { id: claims.displayId }, data: { authToken: newToken }, }); return newToken; } export async function generateShortCode(displayId: string): Promise { await prisma.displayAuthCode.deleteMany({ where: { displayId }, }); const code = Math.floor(100000 + Math.random() * 900000).toString(); await prisma.displayAuthCode.create({ data: { code, displayId, expiresAt: new Date(Date.now() + 1000 * 60 * 5), }, }); return code; } export async function exchangeCodeForToken(code: string) { const authCode = await prisma.$transaction(async (tx) => { const codeRecord = await tx.displayAuthCode.findUnique({ where: { code }, include: { display: true }, }); if (!codeRecord) return null; await tx.displayAuthCode.delete({ where: { id: codeRecord.id } }); return codeRecord; }); if (!authCode) return null; if (new Date() > authCode.expiresAt) return null; return { token: await createDisplayJWT( authCode.displayId, authCode.display.organizationId ), mode: authCode.display.mode, }; }