Skip to content

Commit 2f90b80

Browse files
feat(mfa): implement MFA flow with authenticator selection and challenge handling
1 parent 4c0ba32 commit 2f90b80

1 file changed

Lines changed: 57 additions & 33 deletions

File tree

example/src/screens/hooks/Home.tsx

Lines changed: 57 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -128,14 +128,65 @@ const HomeScreen = () => {
128128
});
129129
} catch (e: any) {
130130
if (e?.json?.mfa_token) {
131-
setMfaToken(e.json.mfa_token);
132-
setMfaStep('list');
131+
const token = e.json.mfa_token;
132+
setMfaToken(token);
133133
Alert.alert(
134134
'MFA Required',
135-
'Multi-factor authentication is required. Follow the steps below.'
135+
'Multi-factor authentication is required. Checking enrolled authenticators...'
136136
);
137+
await startMfaFlow(token);
138+
} else {
139+
setApiError(e as Error);
137140
}
138-
setApiError(e as Error);
141+
}
142+
};
143+
144+
const startMfaFlow = async (token: string) => {
145+
setMfaLoading(true);
146+
clearResult();
147+
try {
148+
const list = await mfa.getAuthenticators({
149+
mfaToken: token,
150+
factorsAllowed: [
151+
MfaFactorType.OTP,
152+
MfaFactorType.SMS,
153+
MfaFactorType.EMAIL,
154+
MfaFactorType.PUSH,
155+
MfaFactorType.VOICE,
156+
],
157+
});
158+
setAuthenticators(list);
159+
160+
const activeAuthenticator = list.find((auth) => auth.active);
161+
if (activeAuthenticator) {
162+
setSelectedAuthenticator(activeAuthenticator);
163+
setMfaStep('challenge');
164+
await triggerChallenge(token, activeAuthenticator);
165+
} else {
166+
setMfaStep('enroll-select');
167+
}
168+
} catch (e) {
169+
handleMfaError(e, 'Failed to list authenticators.');
170+
setMfaStep('idle');
171+
} finally {
172+
setMfaLoading(false);
173+
}
174+
};
175+
176+
const triggerChallenge = async (token: string, auth: MfaAuthenticator) => {
177+
setMfaLoading(true);
178+
try {
179+
const res = await mfa.challenge({
180+
mfaToken: token,
181+
authenticatorId: auth.id,
182+
});
183+
setChallengeResult(res);
184+
setMfaStep('verify');
185+
} catch (e) {
186+
handleMfaError(e, 'Challenge failed.');
187+
setMfaStep('list');
188+
} finally {
189+
setMfaLoading(false);
139190
}
140191
};
141192

@@ -179,41 +230,14 @@ const HomeScreen = () => {
179230
};
180231

181232
const onStartMfa = async () => {
182-
setMfaLoading(true);
183-
clearResult();
184-
try {
185-
const list = await mfa.getAuthenticators({ mfaToken });
186-
setAuthenticators(list);
187-
setMfaStep('list');
188-
} catch (e) {
189-
handleMfaError(e, 'Failed to list authenticators.');
190-
} finally {
191-
setMfaLoading(false);
192-
}
233+
await startMfaFlow(mfaToken);
193234
};
194235

195236
const onSelectAuthenticator = (auth: MfaAuthenticator) => {
196237
setSelectedAuthenticator(auth);
197238
setChallengeResult(null);
198239
setMfaStep('challenge');
199-
onChallenge(auth);
200-
};
201-
202-
const onChallenge = async (auth: MfaAuthenticator) => {
203-
setMfaLoading(true);
204-
try {
205-
const result = await mfa.challenge({
206-
mfaToken,
207-
authenticatorId: auth.id,
208-
});
209-
setChallengeResult(result);
210-
setMfaStep('verify');
211-
} catch (e) {
212-
handleMfaError(e, 'Challenge failed.');
213-
setMfaStep('list');
214-
} finally {
215-
setMfaLoading(false);
216-
}
240+
triggerChallenge(mfaToken, auth);
217241
};
218242

219243
const onSelectEnrollType = (type: EnrollType) => {

0 commit comments

Comments
 (0)