@@ -3,7 +3,7 @@ import { PermissionAction } from '@supabase/shared-types/out/constants'
33import { useEffect , useState } from 'react'
44import { useForm } from 'react-hook-form'
55import { toast } from 'sonner'
6- import { number , object , string } from 'yup'
6+ import { number , object , string , boolean } from 'yup'
77
88import { useParams } from 'common'
99import { ScaffoldSection , ScaffoldSectionTitle } from 'components/layouts/Scaffold'
@@ -32,6 +32,7 @@ import {
3232 SelectTrigger_Shadcn_ ,
3333 SelectValue_Shadcn_ ,
3434 Select_Shadcn_ ,
35+ Switch ,
3536 WarningIcon ,
3637} from 'ui'
3738import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
@@ -79,6 +80,10 @@ const phoneSchema = object({
7980 MFA_PHONE_TEMPLATE : string ( ) . required ( 'SMS template is required.' ) ,
8081} )
8182
83+ const securitySchema = object ( {
84+ MFA_ALLOW_LOW_AAL : boolean ( ) . required ( ) ,
85+ } )
86+
8287const MfaAuthSettingsForm = ( ) => {
8388 const { ref : projectRef } = useParams ( )
8489 const { data : authConfig , error : authConfigError , isError } = useAuthConfigQuery ( { projectRef } )
@@ -87,6 +92,7 @@ const MfaAuthSettingsForm = () => {
8792 // Separate loading states for each form
8893 const [ isUpdatingTotpForm , setIsUpdatingTotpForm ] = useState ( false )
8994 const [ isUpdatingPhoneForm , setIsUpdatingPhoneForm ] = useState ( false )
95+ const [ isUpdatingSecurityForm , setIsUpdatingSecurityForm ] = useState ( false )
9096
9197 const [ isConfirmationModalVisible , setIsConfirmationModalVisible ] = useState ( false )
9298
@@ -126,6 +132,13 @@ const MfaAuthSettingsForm = () => {
126132 } ,
127133 } )
128134
135+ const securityForm = useForm ( {
136+ resolver : yupResolver ( securitySchema ) ,
137+ defaultValues : {
138+ MFA_ALLOW_LOW_AAL : false ,
139+ } ,
140+ } )
141+
129142 useEffect ( ( ) => {
130143 if ( authConfig ) {
131144 if ( ! isUpdatingTotpForm ) {
@@ -150,8 +163,14 @@ const MfaAuthSettingsForm = () => {
150163 MFA_PHONE_TEMPLATE : authConfig ?. MFA_PHONE_TEMPLATE || 'Your code is {{ .Code }}' ,
151164 } )
152165 }
166+
167+ if ( ! isUpdatingSecurityForm ) {
168+ securityForm . reset ( {
169+ MFA_ALLOW_LOW_AAL : authConfig ?. MFA_ALLOW_LOW_AAL ?? true ,
170+ } )
171+ }
153172 }
154- } , [ authConfig , isUpdatingTotpForm , isUpdatingPhoneForm ] )
173+ } , [ authConfig , isUpdatingTotpForm , isUpdatingPhoneForm , isUpdatingSecurityForm ] )
155174
156175 const onSubmitTotpForm = ( values : any ) => {
157176 const { verifyEnabled : MFA_TOTP_VERIFY_ENABLED , enrollEnabled : MFA_TOTP_ENROLL_ENABLED } =
@@ -181,6 +200,26 @@ const MfaAuthSettingsForm = () => {
181200 )
182201 }
183202
203+ const onSubmitSecurityForm = ( values : any ) => {
204+ const payload = { ...values }
205+
206+ setIsUpdatingSecurityForm ( true )
207+
208+ updateAuthConfig (
209+ { projectRef : projectRef ! , config : payload } ,
210+ {
211+ onError : ( error ) => {
212+ toast . error ( `Failed to update phone MFA settings: ${ error ?. message } ` )
213+ setIsUpdatingSecurityForm ( false )
214+ } ,
215+ onSuccess : ( ) => {
216+ toast . success ( 'Successfully updated phone MFA settings' )
217+ setIsUpdatingSecurityForm ( false )
218+ } ,
219+ }
220+ )
221+ }
222+
184223 const onSubmitPhoneForm = ( values : any ) => {
185224 let payload = { ...values }
186225
@@ -461,6 +500,7 @@ const MfaAuthSettingsForm = () => {
461500 </ form >
462501 </ Form_Shadcn_ >
463502 </ ScaffoldSection >
503+
464504 < ConfirmationModal
465505 visible = { isConfirmationModalVisible }
466506 title = "Confirm SMS MFA"
@@ -480,6 +520,55 @@ const MfaAuthSettingsForm = () => {
480520 customers are using SMS MFA.
481521 </ p >
482522 </ ConfirmationModal >
523+
524+ < ScaffoldSection isFullWidth >
525+ < ScaffoldSectionTitle className = "mb-4" > Enhanced MFA Security</ ScaffoldSectionTitle >
526+
527+ < Form_Shadcn_ { ...securityForm } >
528+ < form onSubmit = { securityForm . handleSubmit ( onSubmitSecurityForm ) } className = "space-y-4" >
529+ < Card >
530+ < CardContent className = "pt-6" >
531+ < FormField_Shadcn_
532+ control = { securityForm . control }
533+ name = "MFA_ALLOW_LOW_AAL"
534+ render = { ( { field } ) => (
535+ < FormItemLayout
536+ layout = "flex-row-reverse"
537+ label = "Limit duration of AAL1 sessions"
538+ description = "A user's session will be terminated unless they verify one of their factors within 15 minutes of initial sign in. Recommendation: ON"
539+ >
540+ < FormControl_Shadcn_ >
541+ < Switch
542+ checked = { ! field . value }
543+ onCheckedChange = { ( value ) => field . onChange ( ! value ) }
544+ disabled = { ! canUpdateConfig }
545+ />
546+ </ FormControl_Shadcn_ >
547+ </ FormItemLayout >
548+ ) }
549+ />
550+ </ CardContent >
551+ < CardFooter className = "justify-end space-x-2" >
552+ { securityForm . formState . isDirty && (
553+ < Button type = "default" onClick = { ( ) => securityForm . reset ( ) } >
554+ Cancel
555+ </ Button >
556+ ) }
557+ < Button
558+ type = "primary"
559+ htmlType = "submit"
560+ disabled = {
561+ ! canUpdateConfig || isUpdatingSecurityForm || ! securityForm . formState . isDirty
562+ }
563+ loading = { isUpdatingPhoneForm }
564+ >
565+ Save changes
566+ </ Button >
567+ </ CardFooter >
568+ </ Card >
569+ </ form >
570+ </ Form_Shadcn_ >
571+ </ ScaffoldSection >
483572 </ >
484573 )
485574}
0 commit comments