-- Create security definer function to block AAL1 sessions when MFA is enrolled CREATE OR REPLACE FUNCTION public.block_aal1_with_mfa() RETURNS boolean LANGUAGE sql STABLE SECURITY DEFINER SET search_path = public AS $$ SELECT CASE -- If current session is AAL1 WHEN (auth.jwt() ->> 'aal') = 'aal1' THEN -- Check if user has verified MFA factors NOT EXISTS ( SELECT 1 FROM auth.mfa_factors WHERE user_id = auth.uid() AND status = 'verified' ) -- If AAL2 or higher, allow ELSE true END; $$; -- Apply to profiles table CREATE POLICY "enforce_aal2_for_mfa_users" ON public.profiles FOR ALL USING (public.block_aal1_with_mfa()); -- Apply to user_roles table CREATE POLICY "enforce_aal2_for_mfa_users_roles" ON public.user_roles FOR ALL USING (public.block_aal1_with_mfa()); -- Apply to submission tables CREATE POLICY "enforce_aal2_for_mfa_users_park_sub" ON public.park_submissions FOR ALL USING (public.block_aal1_with_mfa()); CREATE POLICY "enforce_aal2_for_mfa_users_ride_sub" ON public.ride_submissions FOR ALL USING (public.block_aal1_with_mfa()); CREATE POLICY "enforce_aal2_for_mfa_users_company_sub" ON public.company_submissions FOR ALL USING (public.block_aal1_with_mfa()); CREATE POLICY "enforce_aal2_for_mfa_users_content_sub" ON public.content_submissions FOR ALL USING (public.block_aal1_with_mfa()); CREATE POLICY "enforce_aal2_for_mfa_users_photo_sub" ON public.photo_submissions FOR ALL USING (public.block_aal1_with_mfa()); -- Apply to user content tables CREATE POLICY "enforce_aal2_for_mfa_users_reviews" ON public.reviews FOR ALL USING (public.block_aal1_with_mfa()); CREATE POLICY "enforce_aal2_for_mfa_users_reports" ON public.reports FOR ALL USING (public.block_aal1_with_mfa()); -- Grant execute permission GRANT EXECUTE ON FUNCTION public.block_aal1_with_mfa() TO authenticated;