// 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<string> {
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<DisplayJWTPayload> {
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<string> {
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,
};
}