Skip to content

Commit 0403429

Browse files
authored
feat(core): bind SMS MFA (#7662)
1 parent 20522a1 commit 0403429

File tree

5 files changed

+155
-79
lines changed

5 files changed

+155
-79
lines changed

packages/core/src/routes/experience/classes/helpers.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ export const getAllUserEnabledMfaVerifications = (
212212
}
213213

214214
const email = currentProfile?.primaryEmail ?? user.primaryEmail;
215+
const phone = currentProfile?.primaryPhone ?? user.primaryPhone;
215216

216217
const implicitVerifications = [
217218
// Email MFA Factor: user has primaryEmail + Email factor enabled in SIE
@@ -224,6 +225,16 @@ export const getAllUserEnabledMfaVerifications = (
224225
},
225226
] satisfies MfaVerification[])
226227
: []),
228+
// Phone MFA Factor: user has primaryPhone + Phone factor enabled in SIE
229+
...(mfaSettings.factors.includes(MfaFactor.PhoneVerificationCode) && phone
230+
? ([
231+
{
232+
id: 'implicit-phone-mfa', // Fake ID for capability
233+
type: MfaFactor.PhoneVerificationCode,
234+
createdAt: new Date(user.createdAt).toISOString(),
235+
},
236+
] satisfies MfaVerification[])
237+
: []),
227238
];
228239

229240
return [...storedVerifications, ...implicitVerifications];

packages/core/src/routes/experience/classes/libraries/mfa-validator.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ import {
1111

1212
import { getAllUserEnabledMfaVerifications } from '../helpers.js';
1313
import { type BackupCodeVerification } from '../verifications/backup-code-verification.js';
14-
import { type EmailCodeVerification } from '../verifications/code-verification.js';
14+
import {
15+
type EmailCodeVerification,
16+
type PhoneCodeVerification,
17+
} from '../verifications/code-verification.js';
1518
import { type VerificationRecord } from '../verifications/index.js';
1619
import { type TotpVerification } from '../verifications/totp-verification.js';
1720
import { type WebAuthnVerification } from '../verifications/web-authn-verification.js';
@@ -21,26 +24,30 @@ const mfaVerificationTypes = Object.freeze([
2124
VerificationType.BackupCode,
2225
VerificationType.WebAuthn,
2326
VerificationType.EmailVerificationCode,
27+
VerificationType.PhoneVerificationCode,
2428
]);
2529

2630
type MfaVerificationType =
2731
| VerificationType.TOTP
2832
| VerificationType.BackupCode
2933
| VerificationType.WebAuthn
30-
| VerificationType.EmailVerificationCode;
34+
| VerificationType.EmailVerificationCode
35+
| VerificationType.PhoneVerificationCode;
3136

3237
const mfaVerificationTypeToMfaFactorMap = Object.freeze({
3338
[VerificationType.TOTP]: MfaFactor.TOTP,
3439
[VerificationType.BackupCode]: MfaFactor.BackupCode,
3540
[VerificationType.WebAuthn]: MfaFactor.WebAuthn,
3641
[VerificationType.EmailVerificationCode]: MfaFactor.EmailVerificationCode,
42+
[VerificationType.PhoneVerificationCode]: MfaFactor.PhoneVerificationCode,
3743
}) satisfies Record<MfaVerificationType, MfaFactor>;
3844

3945
type MfaVerificationRecord =
4046
| TotpVerification
4147
| WebAuthnVerification
4248
| BackupCodeVerification
43-
| EmailCodeVerification;
49+
| EmailCodeVerification
50+
| PhoneCodeVerification;
4451

4552
const isMfaVerificationRecord = (
4653
verification: VerificationRecord

packages/core/src/routes/experience/profile-routes.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -231,8 +231,16 @@ export default function interactionProfileRoutes<T extends ExperienceInteraction
231231
break;
232232
}
233233
case MfaFactor.PhoneVerificationCode: {
234-
// TODO: Implement SMS verification code MFA binding
235-
throw new Error('Not implemented yet');
234+
if (!EnvSet.values.isDevFeaturesEnabled) {
235+
throw new Error('Not implemented yet');
236+
}
237+
238+
await experienceInteraction.profile.setProfileByVerificationId(
239+
SignInIdentifier.Phone,
240+
verificationId,
241+
log
242+
);
243+
break;
236244
}
237245
}
238246

packages/integration-tests/src/helpers/sign-in-experience.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,22 @@ export const enableMandatoryMfaWithEmailAndBackupCode = async () =>
185185
},
186186
});
187187

188+
export const enableMandatoryMfaWithPhone = async () =>
189+
updateSignInExperience({
190+
mfa: {
191+
factors: [MfaFactor.PhoneVerificationCode],
192+
policy: MfaPolicy.Mandatory,
193+
},
194+
});
195+
196+
export const enableMandatoryMfaWithPhoneAndBackupCode = async () =>
197+
updateSignInExperience({
198+
mfa: {
199+
factors: [MfaFactor.PhoneVerificationCode, MfaFactor.BackupCode],
200+
policy: MfaPolicy.Mandatory,
201+
},
202+
});
203+
188204
export const enableMandatoryMfaWithWebAuthnAndBackupCode = async () =>
189205
updateSignInExperience({
190206
mfa: {

0 commit comments

Comments
 (0)