From d9a8ce532f2a040779b0207bcca9a068f10dc0e5 Mon Sep 17 00:00:00 2001 From: simoleo89 Date: Sat, 27 Jun 2026 16:44:30 +0200 Subject: [PATCH] Add /client launcher page (auth-gated SSO ticket + embed) Faithful to AtomCMS's NitroController: requires a session (redirects to /login), issues + persists the SSO ticket via issueSsoTicket (auth_ticket + ip_current from x-forwarded-for), and embeds the configured client URL with ?sso=. Ties auth + SSO + settings together. Verified: tsc exit 0, next build exit 0 (/client route). --- src/app/client/page.tsx | 49 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 src/app/client/page.tsx diff --git a/src/app/client/page.tsx b/src/app/client/page.tsx new file mode 100644 index 00000000..6d7ccee3 --- /dev/null +++ b/src/app/client/page.tsx @@ -0,0 +1,49 @@ +import { headers } from "next/headers"; +import { redirect } from "next/navigation"; +import { issueSsoTicket } from "@/lib/auth/sso-ticket"; +import { auth } from "@/lib/auth"; +import { prisma } from "@/lib/prisma"; +import { siteSettings } from "@/lib/services/site-settings"; + +export const dynamic = "force-dynamic"; + +export default async function ClientPage() { + const session = await auth(); + if (!session?.user?.id) redirect("/login"); + + const userId = Number(session.user.id); + const [hotelName, clientUrl] = await Promise.all([ + siteSettings.get("hotel_name", "Atom"), + siteSettings.get("nitro_client_url", ""), + ]); + + const hdrs = await headers(); + const ip = + hdrs.get("x-forwarded-for")?.split(",")[0]?.trim() ?? hdrs.get("x-real-ip") ?? "0.0.0.0"; + + // Faithful to AtomCMS's NitroController: issue (and persist) the SSO ticket on + // the launcher render, then hand it to the client. + const ticket = await issueSsoTicket(prisma, userId, hotelName ?? "Atom", ip); + + const src = clientUrl + ? `${clientUrl}${clientUrl.includes("?") ? "&" : "?"}sso=${encodeURIComponent(ticket)}` + : ""; + + return ( +
+

Launching {hotelName ?? "Atom"}…

+ {src ? ( +