Skip to content

Commit 84f4161

Browse files
bhparijatprameshj
andauthored
sign-in flow for totp (#6626)
* Export TOTP symbols to be picked up by demo app. * adding sign-in flow for totp * using only verification code for sign-in * added startSignInTotp method * modified verification code usage in object signin * added mfa enrollment id to finalize signin method: * adding singin for totp in demoapp * made enrollmentId to not be optional * reverting changes in authapi.md * removed unnecessary check and fixed spelling * added back otp check * made _finalizeEnroll && and _finalizeSignin to be async Co-authored-by: Pavithra Ramesh <[email protected]>
1 parent 3f94477 commit 84f4161

File tree

4 files changed

+121
-7
lines changed

4 files changed

+121
-7
lines changed

packages/auth/demo/public/index.html

+11
Original file line numberDiff line numberDiff line change
@@ -755,6 +755,17 @@ <h4 class="modal-title">Select a second factor to sign in with</h4>
755755
</button>
756756
</div>
757757
</form>
758+
<!-- For handling sign-in with TOTP 2nd factor. -->
759+
<form class="form form-bordered no-submit hidden" id="multi-factor-totp">
760+
<div class="form">
761+
<input type="text" id="multi-factor-totp-sign-in-verification-code"
762+
class="form-control" placeholder="Totp Verification code" />
763+
<button class="btn btn-block btn-primary"
764+
id="sign-in-with-totp-multi-factor">
765+
Complete sign In
766+
</button>
767+
</div>
768+
</form>
758769
</div>
759770
<div class="modal-footer">
760771
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>

packages/auth/demo/src/index.js

+38-1
Original file line numberDiff line numberDiff line change
@@ -1068,6 +1068,7 @@ function handleMultiFactorSignIn(resolver) {
10681068
);
10691069
// Hide phone form (other second factor types could be supported).
10701070
$('#multi-factor-phone').addClass('hidden');
1071+
$('#multi-factor-totp').addClass('hidden');
10711072
// Show second factor recovery dialog.
10721073
$('#multiFactorModal').modal();
10731074
}
@@ -1134,6 +1135,7 @@ function onSelectMultiFactorHint(index) {
11341135
// Hide all forms for handling each type of second factors.
11351136
// Currently only phone is supported.
11361137
$('#multi-factor-phone').addClass('hidden');
1138+
$('#multi-factor-totp').addClass('hidden');
11371139
if (
11381140
!multiFactorErrorResolver ||
11391141
typeof multiFactorErrorResolver.hints[index] === 'undefined'
@@ -1153,6 +1155,14 @@ function onSelectMultiFactorHint(index) {
11531155
// Clear all input.
11541156
$('#multi-factor-sign-in-verification-id').val('');
11551157
$('#multi-factor-sign-in-verification-code').val('');
1158+
} else if (multiFactorErrorResolver.hints[index].factorId === 'totp') {
1159+
// Save selected second factor.
1160+
selectedMultiFactorHint = multiFactorErrorResolver.hints[index];
1161+
1162+
// Show sign-in with totp second factor menu.
1163+
$('#multi-factor-totp').removeClass('hidden');
1164+
// Clear all input.
1165+
$('#multi-factor-totp-sign-in-verification-code').val('');
11561166
} else {
11571167
// 2nd factor not found or not supported by app.
11581168
alertError('Selected 2nd factor is not supported!');
@@ -1207,6 +1217,28 @@ function onFinalizeSignInWithPhoneMultiFactor(event) {
12071217
}, onAuthError);
12081218
}
12091219

1220+
/**
1221+
* Completes sign-in with the 2nd factor totp assertion.
1222+
* @param {!jQuery.Event} event The jQuery event object.
1223+
*/
1224+
function onFinalizeSignInWithTotpMultiFactor(event) {
1225+
event.preventDefault();
1226+
// Make sure a second factor is selected.
1227+
const otp = $('#multi-factor-totp-sign-in-verification-code').val();
1228+
if (!otp || !selectedMultiFactorHint || !multiFactorErrorResolver) {
1229+
return;
1230+
}
1231+
1232+
const assertion = TotpMultiFactorGenerator.assertionForSignIn(
1233+
selectedMultiFactorHint.uid,
1234+
otp
1235+
);
1236+
multiFactorErrorResolver.resolveSignIn(assertion).then(userCredential => {
1237+
onAuthUserCredentialSuccess(userCredential);
1238+
$('#multiFactorModal').modal('hide');
1239+
}, onAuthError);
1240+
}
1241+
12101242
/**
12111243
* Adds a new row to insert an OAuth custom parameter key/value pair.
12121244
* @param {!jQuery.Event} _event The jQuery event object.
@@ -1336,7 +1368,6 @@ function signInWithPopupRedirect(provider) {
13361368
customParameters[key] = value;
13371369
}
13381370
});
1339-
console.log('customParameters: ', customParameters);
13401371
// For older jscore versions that do not support this.
13411372
if (provider.setCustomParameters) {
13421373
// Set custom parameters on current provider.
@@ -1985,6 +2016,12 @@ function initApp() {
19852016
$('#sign-in-with-phone-multi-factor').click(
19862017
onFinalizeSignInWithPhoneMultiFactor
19872018
);
2019+
2020+
// Completes multi-factor sign-in with supplied OTP(One-Time Password).
2021+
$('#sign-in-with-totp-multi-factor').click(
2022+
onFinalizeSignInWithTotpMultiFactor
2023+
);
2024+
19882025
// Starts multi-factor enrollment with phone number.
19892026
$('#enroll-mfa-verify-phone-number').click(onStartEnrollWithPhoneMultiFactor);
19902027
// Completes multi-factor enrollment with supplied SMS code.

packages/auth/src/api/authentication/mfa.ts

+53
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,27 @@ export interface StartPhoneMfaSignInRequest {
5151
};
5252
tenantId?: string;
5353
}
54+
export interface StartTotpMfaSignInRequest {
55+
mfaPendingCredential: string;
56+
mfaEnrollmentId: string;
57+
totpSignInInfo: {
58+
verificationCode: string;
59+
};
60+
tenantId?: string;
61+
}
5462

5563
export interface StartPhoneMfaSignInResponse {
5664
phoneResponseInfo: {
5765
sessionInfo: string;
5866
};
5967
}
6068

69+
export interface StartTotpMfaSignInResponse {
70+
totpSignInInfo: {
71+
verificationCode: string;
72+
};
73+
}
74+
6175
export function startSignInPhoneMfa(
6276
auth: Auth,
6377
request: StartPhoneMfaSignInRequest
@@ -73,14 +87,38 @@ export function startSignInPhoneMfa(
7387
);
7488
}
7589

90+
export function startSignInTotpMfa(
91+
auth: Auth,
92+
request: StartTotpMfaSignInRequest
93+
): Promise<StartTotpMfaSignInResponse> {
94+
return _performApiRequest<
95+
StartTotpMfaSignInRequest,
96+
StartTotpMfaSignInResponse
97+
>(
98+
auth,
99+
HttpMethod.POST,
100+
Endpoint.START_MFA_SIGN_IN,
101+
_addTidIfNecessary(auth, request)
102+
);
103+
}
104+
76105
export interface FinalizePhoneMfaSignInRequest {
77106
mfaPendingCredential: string;
78107
phoneVerificationInfo: SignInWithPhoneNumberRequest;
79108
tenantId?: string;
80109
}
81110

111+
export interface FinalizeTotpMfaSignInRequest {
112+
mfaPendingCredential: string;
113+
totpVerificationInfo: { verificationCode: string };
114+
tenantId?: string;
115+
mfaEnrollmentId: string;
116+
}
117+
82118
export interface FinalizePhoneMfaSignInResponse extends FinalizeMfaResponse {}
83119

120+
export interface FinalizeTotpMfaSignInResponse extends FinalizeMfaResponse {}
121+
84122
export function finalizeSignInPhoneMfa(
85123
auth: Auth,
86124
request: FinalizePhoneMfaSignInRequest
@@ -96,6 +134,21 @@ export function finalizeSignInPhoneMfa(
96134
);
97135
}
98136

137+
export function finalizeSignInTotpMfa(
138+
auth: Auth,
139+
request: FinalizeTotpMfaSignInRequest
140+
): Promise<FinalizeTotpMfaSignInResponse> {
141+
return _performApiRequest<
142+
FinalizeTotpMfaSignInRequest,
143+
FinalizeTotpMfaSignInResponse
144+
>(
145+
auth,
146+
HttpMethod.POST,
147+
Endpoint.FINALIZE_MFA_SIGN_IN,
148+
_addTidIfNecessary(auth, request)
149+
);
150+
}
151+
99152
/**
100153
* @internal
101154
*/

packages/auth/src/mfa/assertions/totp.ts

+19-6
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,10 @@ import {
2626
StartTotpMfaEnrollmentResponse,
2727
TotpVerificationInfo
2828
} from '../../api/account_management/mfa';
29-
import { FinalizeMfaResponse } from '../../api/authentication/mfa';
29+
import {
30+
FinalizeMfaResponse,
31+
finalizeSignInTotpMfa
32+
} from '../../api/authentication/mfa';
3033
import { MultiFactorAssertionImpl } from '../../mfa/mfa_assertion';
3134
import { MultiFactorSessionImpl } from '../mfa_session';
3235
import { AuthErrorCode } from '../../core/errors';
@@ -136,7 +139,7 @@ export class TotpMultiFactorAssertionImpl
136139
}
137140

138141
/** @internal */
139-
_finalizeEnroll(
142+
async _finalizeEnroll(
140143
auth: AuthInternal,
141144
idToken: string,
142145
displayName?: string | null
@@ -154,11 +157,21 @@ export class TotpMultiFactorAssertionImpl
154157
}
155158

156159
/** @internal */
157-
_finalizeSignIn(
158-
_auth: AuthInternal,
159-
_mfaPendingCredential: string
160+
async _finalizeSignIn(
161+
auth: AuthInternal,
162+
mfaPendingCredential: string
160163
): Promise<FinalizeMfaResponse> {
161-
throw new Error('method not implemented');
164+
_assert(
165+
this.enrollmentId !== undefined && this.otp !== undefined,
166+
auth,
167+
AuthErrorCode.ARGUMENT_ERROR
168+
);
169+
const totpVerificationInfo = { verificationCode: this.otp };
170+
return finalizeSignInTotpMfa(auth, {
171+
mfaPendingCredential,
172+
mfaEnrollmentId: this.enrollmentId,
173+
totpVerificationInfo
174+
});
162175
}
163176
}
164177

0 commit comments

Comments
 (0)