page.tsx74 lines · main
1import { notFound } from 'next/navigation';
2
3import { HostedFlow } from './hosted-flow';
4
5const FORM_FLOWS = [
6 'sign-in',
7 'sign-up',
8 'magic-link',
9 'otp',
10 'new-password',
11 'two-factor',
12] as const;
13type FormFlow = (typeof FORM_FLOWS)[number];
14
15function isFormFlow(value: string): value is FormFlow {
16 return (FORM_FLOWS as readonly string[]).includes(value);
17}
18
19export const dynamic = 'force-dynamic';
20
21export async function generateMetadata({
22 params,
23}: {
24 params: Promise<{ flow: string }>;
25}) {
26 const { flow } = await params;
27 if (!isFormFlow(flow)) return { title: 'auth' };
28 return { title: `auth · ${flow}` };
29}
30
31interface PublicConfig {
32 primaryColor: string;
33 senderName: string;
34 socialProviders: string[];
35 customOidc: Array<{ id: string; displayName: string }>;
36 turnstile: { enabled: boolean; siteKey: string | null };
37}
38
39async function fetchPublicConfig(projectId: string): Promise<PublicConfig | null> {
40 try {
41 const res = await fetch(
42 `${process.env.NEXT_PUBLIC_API_URL ?? ''}/v1/projects/${projectId}/auth/branding/config`,
43 { next: { revalidate: 60 } },
44 );
45 if (!res.ok) return null;
46 return (await res.json()) as PublicConfig;
47 } catch {
48 return null;
49 }
50}
51
52export default async function HostedFlowPage({
53 params,
54 searchParams,
55}: {
56 params: Promise<{ projectId: string; flow: string }>;
57 searchParams: Promise<{ callbackURL?: string; token?: string }>;
58}) {
59 const { projectId, flow } = await params;
60 if (!isFormFlow(flow)) notFound();
61 const { callbackURL, token } = await searchParams;
62 // Default to the hosted account page when no callback is provided.
63 const redirectTo = callbackURL || `/auth/${projectId}/account`;
64 const publicConfig = await fetchPublicConfig(projectId);
65 return (
66 <HostedFlow
67 projectId={projectId}
68 flow={flow}
69 callbackURL={redirectTo}
70 token={token}
71 turnstileSiteKey={publicConfig?.turnstile.enabled ? publicConfig.turnstile.siteKey : null}
72 />
73 );
74}