Add a second factor with an authenticator app (TOTP) and require it in your policies.
#Enroll a factor
JavaScript
const { data: f } = await stitchdb.auth.mfa.enroll({ factorType: 'totp', friendlyName: 'My phone' })
// show f.totp.qr_code (an SVG data URL) or f.totp.secret, then verify the first code:
const { data: c } = await stitchdb.auth.mfa.challenge({ factorId: f.id })
await stitchdb.auth.mfa.verify({ factorId: f.id, challengeId: c.id, code: '123456' })#Sign in with a second factor
JavaScript
await stitchdb.auth.signInWithPassword({ email, password })
const { data: aal } = await stitchdb.auth.mfa.getAuthenticatorAssuranceLevel()
if (aal.nextLevel === 'aal2' && aal.currentLevel !== 'aal2') {
const { data: { totp } } = await stitchdb.auth.mfa.listFactors()
await stitchdb.auth.mfa.challengeAndVerify({ factorId: totp[0].id, code: '123456' })
}After verifying, the session's token has aal: 'aal2'.
#Require MFA in a policy
SQL
create policy "MFA required" on public.payouts
as restrictive for all to authenticated
using ((auth.jwt() ->> 'aal') = 'aal2');#Remove a factor
JavaScript
await stitchdb.auth.mfa.unenroll({ factorId })
// admins, with the service_role key:
await admin.auth.admin.mfa.deleteFactor({ userId, id: factorId })#Settings
In Studio → Authentication → Settings: allow enrolling and verifying TOTP factors (both on) and the maximum number of factors per user (default 10, up to 20).
#Phone (SMS) factor
With an SMS provider set up (see Phone sign-in), turn on Allow phone numbers as an MFA factor and Allow phone MFA verification under Authentication → Sign-in methods → Phone.
JavaScript
const { data: f } = await stitchdb.auth.mfa.enroll({ factorType: 'phone', phone: '+15555550100' })
const { data: c } = await stitchdb.auth.mfa.challenge({ factorId: f.id }) // sends the SMS
await stitchdb.auth.mfa.verify({ factorId: f.id, challengeId: c.id, code: '123456' })Test phone numbers apply to phone sign-in only; a phone MFA challenge always sends a real SMS.