Skip to content

Commit 06a0a82

Browse files
bhparijatprameshj
andcommitted
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 3af11d8 commit 06a0a82

File tree

4 files changed

+121
-7
lines changed

4 files changed

+121
-7
lines changed

packages/auth/demo/public/index.html

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -759,6 +759,17 @@ <h4 class="modal-title">Select a second factor to sign in with</h4>
759759
</button>
760760
</div>
761761
</form>
762+
<!-- For handling sign-in with TOTP 2nd factor. -->
763+
<form class="form form-bordered no-submit hidden" id="multi-factor-totp">
764+
<div class="form">
765+
<input type="text" id="multi-factor-totp-sign-in-verification-code"
766+
class="form-control" placeholder="Totp Verification code" />
767+
<button class="btn btn-block btn-primary"
768+
id="sign-in-with-totp-multi-factor">
769+
Complete sign In
770+
</button>
771+
</div>
772+
</form>
762773
</div>
763774
<div class="modal-footer">
764775
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>

packages/auth/demo/src/index.js

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1103,6 +1103,7 @@ function handleMultiFactorSignIn(resolver) {
11031103
);
11041104
// Hide phone form (other second factor types could be supported).
11051105
$('#multi-factor-phone').addClass('hidden');
1106+
$('#multi-factor-totp').addClass('hidden');
11061107
// Show second factor recovery dialog.
11071108
$('#multiFactorModal').modal();
11081109
}
@@ -1169,6 +1170,7 @@ function onSelectMultiFactorHint(index) {
11691170
// Hide all forms for handling each type of second factors.
11701171
// Currently only phone is supported.
11711172
$('#multi-factor-phone').addClass('hidden');
1173+
$('#multi-factor-totp').addClass('hidden');
11721174
if (
11731175
!multiFactorErrorResolver ||
11741176
typeof multiFactorErrorResolver.hints[index] === 'undefined'
@@ -1188,6 +1190,14 @@ function onSelectMultiFactorHint(index) {
11881190
// Clear all input.
11891191
$('#multi-factor-sign-in-verification-id').val('');
11901192
$('#multi-factor-sign-in-verification-code').val('');
1193+
} else if (multiFactorErrorResolver.hints[index].factorId === 'totp') {
1194+
// Save selected second factor.
1195+
selectedMultiFactorHint = multiFactorErrorResolver.hints[index];
1196+
1197+
// Show sign-in with totp second factor menu.
1198+
$('#multi-factor-totp').removeClass('hidden');
1199+
// Clear all input.
1200+
$('#multi-factor-totp-sign-in-verification-code').val('');
11911201
} else {
11921202
// 2nd factor not found or not supported by app.
11931203
alertError('Selected 2nd factor is not supported!');
@@ -1242,6 +1252,28 @@ function onFinalizeSignInWithPhoneMultiFactor(event) {
12421252
}, onAuthError);
12431253
}
12441254

1255+
/**
1256+
* Completes sign-in with the 2nd factor totp assertion.
1257+
* @param {!jQuery.Event} event The jQuery event object.
1258+
*/
1259+
function onFinalizeSignInWithTotpMultiFactor(event) {
1260+
event.preventDefault();
1261+
// Make sure a second factor is selected.
1262+
const otp = $('#multi-factor-totp-sign-in-verification-code').val();
1263+
if (!otp || !selectedMultiFactorHint || !multiFactorErrorResolver) {
1264+
return;
1265+
}
1266+
1267+
const assertion = TotpMultiFactorGenerator.assertionForSignIn(
1268+
selectedMultiFactorHint.uid,
1269+
otp
1270+
);
1271+
multiFactorErrorResolver.resolveSignIn(assertion).then(userCredential => {
1272+
onAuthUserCredentialSuccess(userCredential);
1273+
$('#multiFactorModal').modal('hide');
1274+
}, onAuthError);
1275+
}
1276+
12451277
/**
12461278
* Adds a new row to insert an OAuth custom parameter key/value pair.
12471279
* @param {!jQuery.Event} _event The jQuery event object.
@@ -1373,7 +1405,6 @@ function signInWithPopupRedirect(provider) {
13731405
customParameters[key] = value;
13741406
}
13751407
});
1376-
console.log('customParameters: ', customParameters);
13771408
// For older jscore versions that do not support this.
13781409
if (provider.setCustomParameters) {
13791410
// Set custom parameters on current provider.
@@ -2046,6 +2077,12 @@ function initApp() {
20462077
$('#sign-in-with-phone-multi-factor').click(
20472078
onFinalizeSignInWithPhoneMultiFactor
20482079
);
2080+
2081+
// Completes multi-factor sign-in with supplied OTP(One-Time Password).
2082+
$('#sign-in-with-totp-multi-factor').click(
2083+
onFinalizeSignInWithTotpMultiFactor
2084+
);
2085+
20492086
// Starts multi-factor enrollment with phone number.
20502087
$('#enroll-mfa-verify-phone-number').click(onStartEnrollWithPhoneMultiFactor);
20512088
// Completes multi-factor enrollment with supplied SMS code.

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

Lines changed: 53 additions & 0 deletions
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

Lines changed: 19 additions & 6 deletions
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)