import { redirect } from 'next/navigation'; import { createSupabaseServerClient } from '@/lib/supabase/server'; import { safeNextPath } from '@/lib/auth/mfa'; import { ChallengeClient } from './challenge-client'; export const dynamic = 'force-dynamic'; /** * AAL2 step-up challenge. The middleware sends authenticated aal1 users here * when they have verified factors. Users with no verified factors are sent to * enrollment instead; users already at aal2 are forwarded to their target. */ export default async function ChallengePage({ searchParams, }: { searchParams: { next?: string }; }) { const supabase = createSupabaseServerClient(); const { data: { user }, } = await supabase.auth.getUser(); if (!user) redirect('/login'); const next = safeNextPath(searchParams.next); const { data: aal } = await supabase.auth.mfa.getAuthenticatorAssuranceLevel(); if (aal?.currentLevel === 'aal2') redirect(next); const { data: factors } = await supabase.auth.mfa.listFactors(); const verified = factors?.all.filter((f) => f.status === 'verified') ?? []; if (verified.length === 0) redirect('/security/enroll'); const totp = verified.find((f) => f.factor_type === 'totp'); const passkey = verified.find((f) => f.factor_type === 'webauthn'); return (

Verify it's you

Complete two-factor authentication to continue.

); }