Skip to content

Commit 90b5f04

Browse files
authored
feat(auth): Multi-factor Auth support with SMS for Google Cloud Identity Platform (firebase#2725)
Defines multi-factor auth client APIs for Google Cloud Identity Platform.
1 parent 9d593bc commit 90b5f04

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+12586
-829
lines changed

packages/auth-types/index.d.ts

+89-1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export interface User extends UserInfo {
3535
linkWithPopup(provider: AuthProvider): Promise<UserCredential>;
3636
linkWithRedirect(provider: AuthProvider): Promise<void>;
3737
metadata: UserMetadata;
38+
multiFactor: MultiFactorUser;
3839
phoneNumber: string | null;
3940
providerData: (UserInfo | null)[];
4041
reauthenticateAndRetrieveDataWithCredential(
@@ -64,6 +65,10 @@ export interface User extends UserInfo {
6465
displayName?: string | null;
6566
photoURL?: string | null;
6667
}): Promise<void>;
68+
verifyBeforeUpdateEmail(
69+
newEmail: string,
70+
actionCodeSettings?: ActionCodeSettings | null
71+
): Promise<void>;
6772
}
6873

6974
export interface UserInfo {
@@ -75,17 +80,31 @@ export interface UserInfo {
7580
uid: string;
7681
}
7782

83+
export interface MultiFactorUser {
84+
enrolledFactors: MultiFactorInfo[];
85+
enroll(
86+
assertion: MultiFactorAssertion,
87+
displayName?: string | null
88+
): Promise<void>;
89+
getSession(): Promise<MultiFactorSession>;
90+
unenroll(option: MultiFactorInfo | string): Promise<void>;
91+
}
92+
7893
export class ActionCodeInfo {
7994
private constructor();
8095
data: {
8196
email?: string | null;
8297
fromEmail?: string | null;
98+
multiFactorInfo?: MultiFactorInfo | null;
99+
previousEmail?: string | null;
83100
};
84101
operation: string;
85102
static Operation: {
86103
PASSWORD_RESET: Operation;
87104
RECOVER_EMAIL: Operation;
88105
EMAIL_SIGNIN: Operation;
106+
REVERT_SECOND_FACTOR_ADDITION: Operation;
107+
VERIFY_AND_CHANGE_EMAIL: Operation;
89108
VERIFY_EMAIL: Operation;
90109
};
91110
}
@@ -164,6 +183,10 @@ export interface AuthError extends Error {
164183
tenantId?: string;
165184
}
166185

186+
export interface MultiFactorError extends AuthError {
187+
resolver: MultiFactorResolver;
188+
}
189+
167190
export class FacebookAuthProvider extends FacebookAuthProvider_Instance {
168191
static PROVIDER_ID: string;
169192
static FACEBOOK_SIGN_IN_METHOD: string;
@@ -206,6 +229,7 @@ export interface IdTokenResult {
206229
authTime: string;
207230
issuedAtTime: string;
208231
signInProvider: string | null;
232+
signInSecondFactor: string | null;
209233
claims: {
210234
[key: string]: any;
211235
};
@@ -239,11 +263,31 @@ export class PhoneAuthProvider_Instance implements AuthProvider {
239263
constructor(auth?: FirebaseAuth | null);
240264
providerId: string;
241265
verifyPhoneNumber(
242-
phoneNumber: string,
266+
phoneInfoOptions: PhoneInfoOptions | string,
243267
applicationVerifier: ApplicationVerifier
244268
): Promise<string>;
245269
}
246270

271+
export type PhoneInfoOptions =
272+
| PhoneSingleFactorInfoOptions
273+
| PhoneMultiFactorEnrollInfoOptions
274+
| PhoneMultiFactorSignInInfoOptions;
275+
276+
export interface PhoneSingleFactorInfoOptions {
277+
phoneNumber: string;
278+
}
279+
280+
export interface PhoneMultiFactorEnrollInfoOptions {
281+
phoneNumber: string;
282+
session: MultiFactorSession;
283+
}
284+
285+
export interface PhoneMultiFactorSignInInfoOptions {
286+
multiFactorHint?: MultiFactorInfo;
287+
multiFactorUid?: string;
288+
session: MultiFactorSession;
289+
}
290+
247291
export class RecaptchaVerifier extends RecaptchaVerifier_Instance {}
248292
export class RecaptchaVerifier_Instance implements ApplicationVerifier {
249293
constructor(
@@ -296,10 +340,53 @@ export interface OAuthCredentialOptions {
296340
rawNonce?: string;
297341
}
298342

343+
export class PhoneAuthCredential extends AuthCredential {
344+
private constructor();
345+
}
346+
299347
export interface AuthSettings {
300348
appVerificationDisabledForTesting: boolean;
301349
}
302350

351+
export class MultiFactorSession {
352+
private constructor();
353+
}
354+
355+
export abstract class MultiFactorAssertion {
356+
factorId: string;
357+
}
358+
359+
export class MultiFactorResolver {
360+
private constructor();
361+
auth: FirebaseAuth;
362+
session: MultiFactorSession;
363+
hints: MultiFactorInfo[];
364+
resolveSignIn(assertion: MultiFactorAssertion): Promise<UserCredential>;
365+
}
366+
367+
export interface MultiFactorInfo {
368+
uid: string;
369+
displayName?: string | null;
370+
enrollmentTime: string;
371+
factorId: string;
372+
}
373+
374+
export interface PhoneMultiFactorInfo extends MultiFactorInfo {
375+
phoneNumber: string;
376+
}
377+
378+
export class PhoneMultiFactorAssertion extends MultiFactorAssertion {
379+
private constructor();
380+
}
381+
382+
export class PhoneMultiFactorGenerator {
383+
private constructor();
384+
static FACTOR_ID: string;
385+
static assertion(
386+
phoneAuthCredential: PhoneAuthCredential
387+
): PhoneMultiFactorAssertion;
388+
}
389+
303390
export class FirebaseAuth {
304391
private constructor();
305392

@@ -386,6 +473,7 @@ declare module '@firebase/app-types' {
386473
SAMLAuthProvider: typeof SAMLAuthProvider;
387474
PhoneAuthProvider: typeof PhoneAuthProvider;
388475
PhoneAuthProvider_Instance: typeof PhoneAuthProvider_Instance;
476+
PhoneMultiFactorGenerator: typeof PhoneMultiFactorGenerator;
389477
RecaptchaVerifier: typeof RecaptchaVerifier;
390478
RecaptchaVerifier_Instance: typeof RecaptchaVerifier_Instance;
391479
TwitterAuthProvider: typeof TwitterAuthProvider;

packages/auth/demo/public/index.html

+80
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,16 @@
112112
title="Email Not Verified" data-placement="bottom">
113113
<i class="fa fa-times"></i>
114114
</span>
115+
<div class="btn-group" id="enrolled-factors-drop-down">
116+
<button type="button" class="btn btn-default btn-sm dropdown-toggle"
117+
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
118+
<i class="fa fa-key" title="User multi-factor enrolled"
119+
data-toggle="tooltip" data-placement="bottom"></i>
120+
<span class="caret"></span>
121+
</button>
122+
<!-- List of enrolled second factors. -->
123+
<div class="dropdown-menu enrolled-second-factors"></div>
124+
</div>
115125
</div>
116126
<div class="clearfix"></div>
117127
</div>
@@ -469,6 +479,37 @@
469479
</button>
470480
</form>
471481

482+
<!-- Enroll MFA-->
483+
<div class="group">Enroll Second Factor</div>
484+
<ul id="mfa-tab-menu" class="nav nav-tabs" role="tablist">
485+
<li role="presentation" class="active">
486+
<a href="#mfa-phone-section" aria-controls="mfa-phone-section"
487+
data-toggle="tab" role="tab">
488+
Phone
489+
</a>
490+
</li>
491+
</ul>
492+
<div class="tab-content">
493+
<div class="tab-pane active" id="mfa-phone-section">
494+
<form class="form form-bordered no-submit">
495+
<input type="tel" id="enroll-mfa-phone-number"
496+
class="form-control" placeholder="Phone Number" />
497+
<button class="btn btn-block btn-primary" id="enroll-mfa-verify-phone-number">
498+
Verify Phone Number
499+
</button>
500+
<input type="text" id="enroll-mfa-phone-verification-id"
501+
class="form-control" placeholder="Phone Verification ID" />
502+
<input type="text" id="enroll-mfa-phone-verification-code"
503+
class="form-control" placeholder="Phone Verification Code" />
504+
<input type="text" id="enroll-mfa-phone-display-name"
505+
class="form-control" placeholder="Display Name" />
506+
<button class="btn btn-block btn-primary"
507+
id="enroll-mfa-confirm-phone-verification">
508+
Complete Enrollment
509+
</button>
510+
</form>
511+
</div>
512+
</div>
472513

473514
<!-- Other Actions -->
474515
<div class="group">Other Actions</div>
@@ -662,6 +703,45 @@
662703
</div>
663704
</div>
664705

706+
<!-- The multi-factor sign-in dialog. -->
707+
<div class="modal" id="multiFactorModal" tabindex="-1" role="dialog">
708+
<div class="modal-dialog" role="document">
709+
<div class="modal-content">
710+
<div class="modal-header">
711+
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
712+
<span aria-hidden="true">&times;</span>
713+
</button>
714+
<h4 class="modal-title">Select a second factor to sign in with</h4>
715+
</div>
716+
<div class="modal-body">
717+
<!-- List of 2nd factor options. -->
718+
<div class="list-group enrolled-second-factors"></div>
719+
<!-- For handling sign-in with phone 2nd factor. -->
720+
<form class="form form-bordered no-submit hidden" id="multi-factor-phone">
721+
<div class="form">
722+
<button class="btn btn-block btn-primary" id="send-2fa-phone-code">
723+
Send code
724+
</button>
725+
</div>
726+
<div class="form">
727+
<input type="text" id="multi-factor-sign-in-verification-id"
728+
class="form-control" placeholder="Phone Verification ID" />
729+
<input type="text" id="multi-factor-sign-in-verification-code"
730+
class="form-control" placeholder="Phone Verification code" />
731+
<button class="btn btn-block btn-primary"
732+
id="sign-in-with-phone-multi-factor">
733+
Complete sign In
734+
</button>
735+
</div>
736+
</form>
737+
</div>
738+
<div class="modal-footer">
739+
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
740+
</div>
741+
</div>
742+
</div>
743+
</div>
744+
665745
<!-- List of provider ID suggestions. -->
666746
<datalist id="provider-id-options">
667747
<option value="google.com"></option>

0 commit comments

Comments
 (0)