LiveDisplayX / src / lib / auth.ts
auth.ts
Raw
// 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,
  };
}