Skip to content

Commit d8bf818

Browse files
authored
feat(auth): expose the missing MultiFactor classes through the universal package (#9194)
* feat(auth): expose the missing MutliFactor classes through the universal package * feat(auth): add documentation
1 parent 96d35df commit d8bf818

File tree

7 files changed

+155
-34
lines changed

7 files changed

+155
-34
lines changed

packages/firebase_auth/firebase_auth/lib/firebase_auth.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ import 'package:flutter/foundation.dart';
1414
export 'package:firebase_auth_platform_interface/firebase_auth_platform_interface.dart'
1515
show
1616
FirebaseAuthException,
17-
FirebaseAuthMultiFactorException,
1817
MultiFactorInfo,
18+
MultiFactorSession,
1919
PhoneMultiFactorInfo,
2020
IdTokenResult,
2121
UserMetadata,

packages/firebase_auth/firebase_auth/lib/src/firebase_auth.dart

Lines changed: 62 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -492,10 +492,16 @@ class FirebaseAuth extends FirebasePluginPlatform {
492492
/// - Thrown if the credential is a [PhoneAuthProvider.credential] and the
493493
/// verification ID of the credential is not valid.id.
494494
Future<UserCredential> signInWithCredential(AuthCredential credential) async {
495-
return UserCredential._(
496-
this,
497-
await _delegate.signInWithCredential(credential),
498-
);
495+
try {
496+
return UserCredential._(
497+
this,
498+
await _delegate.signInWithCredential(credential),
499+
);
500+
} on FirebaseAuthMultiFactorExceptionPlatform catch (e) {
501+
throw FirebaseAuthMultiFactorException._(this, e);
502+
} catch (e) {
503+
rethrow;
504+
}
499505
}
500506

501507
/// Tries to sign in a user with a given custom token.
@@ -519,7 +525,14 @@ class FirebaseAuth extends FirebasePluginPlatform {
519525
/// - **invalid-custom-token**:
520526
/// - Thrown if the custom token format is incorrect.
521527
Future<UserCredential> signInWithCustomToken(String token) async {
522-
return UserCredential._(this, await _delegate.signInWithCustomToken(token));
528+
try {
529+
return UserCredential._(
530+
this, await _delegate.signInWithCustomToken(token));
531+
} on FirebaseAuthMultiFactorExceptionPlatform catch (e) {
532+
throw FirebaseAuthMultiFactorException._(this, e);
533+
} catch (e) {
534+
rethrow;
535+
}
523536
}
524537

525538
/// Attempts to sign in a user with the given email address and password.
@@ -545,10 +558,16 @@ class FirebaseAuth extends FirebasePluginPlatform {
545558
required String email,
546559
required String password,
547560
}) async {
548-
return UserCredential._(
549-
this,
550-
await _delegate.signInWithEmailAndPassword(email, password),
551-
);
561+
try {
562+
return UserCredential._(
563+
this,
564+
await _delegate.signInWithEmailAndPassword(email, password),
565+
);
566+
} on FirebaseAuthMultiFactorExceptionPlatform catch (e) {
567+
throw FirebaseAuthMultiFactorException._(this, e);
568+
} catch (e) {
569+
rethrow;
570+
}
552571
}
553572

554573
/// Signs in using an email address and email sign-in link.
@@ -570,10 +589,16 @@ class FirebaseAuth extends FirebasePluginPlatform {
570589
required String email,
571590
required String emailLink,
572591
}) async {
573-
return UserCredential._(
574-
this,
575-
await _delegate.signInWithEmailLink(email, emailLink),
576-
);
592+
try {
593+
return UserCredential._(
594+
this,
595+
await _delegate.signInWithEmailLink(email, emailLink),
596+
);
597+
} on FirebaseAuthMultiFactorExceptionPlatform catch (e) {
598+
throw FirebaseAuthMultiFactorException._(this, e);
599+
} catch (e) {
600+
rethrow;
601+
}
577602
}
578603

579604
/// Signs in with an AuthProvider using native authentication flow.
@@ -584,10 +609,16 @@ class FirebaseAuth extends FirebasePluginPlatform {
584609
Future<UserCredential> signInWithAuthProvider(
585610
AuthProvider provider,
586611
) async {
587-
return UserCredential._(
588-
this,
589-
await _delegate.signInWithAuthProvider(provider),
590-
);
612+
try {
613+
return UserCredential._(
614+
this,
615+
await _delegate.signInWithAuthProvider(provider),
616+
);
617+
} on FirebaseAuthMultiFactorExceptionPlatform catch (e) {
618+
throw FirebaseAuthMultiFactorException._(this, e);
619+
} catch (e) {
620+
rethrow;
621+
}
591622
}
592623

593624
/// Starts a sign-in flow for a phone number.
@@ -624,15 +655,27 @@ class FirebaseAuth extends FirebasePluginPlatform {
624655
///
625656
/// This method is only available on web based platforms.
626657
Future<UserCredential> signInWithPopup(AuthProvider provider) async {
627-
return UserCredential._(this, await _delegate.signInWithPopup(provider));
658+
try {
659+
return UserCredential._(this, await _delegate.signInWithPopup(provider));
660+
} on FirebaseAuthMultiFactorExceptionPlatform catch (e) {
661+
throw FirebaseAuthMultiFactorException._(this, e);
662+
} catch (e) {
663+
rethrow;
664+
}
628665
}
629666

630667
/// Authenticates a Firebase client using a full-page redirect flow.
631668
///
632669
/// To handle the results and errors for this operation, refer to
633670
/// [getRedirectResult].
634671
Future<void> signInWithRedirect(AuthProvider provider) {
635-
return _delegate.signInWithRedirect(provider);
672+
try {
673+
return _delegate.signInWithRedirect(provider);
674+
} on FirebaseAuthMultiFactorExceptionPlatform catch (e) {
675+
throw FirebaseAuthMultiFactorException._(this, e);
676+
} catch (e) {
677+
rethrow;
678+
}
636679
}
637680

638681
/// Signs out the current user.

packages/firebase_auth/firebase_auth/lib/src/multi_factor.dart

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ class MultiFactor {
1717
///
1818
/// [displayName] can be used to provide a display name for the second factor.
1919
Future<void> enroll(
20-
MultiFactorAssertionPlatform assertion, {
20+
MultiFactorAssertion assertion, {
2121
String? displayName,
2222
}) async {
23-
return _delegate.enroll(assertion, displayName: displayName);
23+
return _delegate.enroll(assertion._delegate, displayName: displayName);
2424
}
2525

2626
/// Unenrolls a second factor from this user.
@@ -45,9 +45,68 @@ class MultiFactor {
4545
class PhoneMultiFactorGenerator {
4646
/// Transforms a PhoneAuthCredential into a [MultiFactorAssertion]
4747
/// which can be used to confirm ownership of a phone second factor.
48-
static MultiFactorAssertionPlatform getAssertion(
48+
static MultiFactorAssertion getAssertion(
4949
PhoneAuthCredential credential,
5050
) {
51-
return PhoneMultiFactorGeneratorPlatform.instance.getAssertion(credential);
51+
final assertion =
52+
PhoneMultiFactorGeneratorPlatform.instance.getAssertion(credential);
53+
return MultiFactorAssertion._(assertion);
5254
}
5355
}
56+
57+
/// Represents an assertion that the Firebase Authentication server
58+
/// can use to authenticate a user as part of a multi-factor flow.
59+
class MultiFactorAssertion {
60+
final MultiFactorAssertionPlatform _delegate;
61+
62+
MultiFactorAssertion._(this._delegate) {
63+
MultiFactorAssertionPlatform.verifyExtends(_delegate);
64+
}
65+
}
66+
67+
/// Utility class that contains methods to resolve second factor
68+
/// requirements on users that have opted into two-factor authentication.
69+
class MultiFactorResolver {
70+
final FirebaseAuth _auth;
71+
final MultiFactorResolverPlatform _delegate;
72+
73+
MultiFactorResolver._(this._auth, this._delegate) {
74+
MultiFactorResolverPlatform.verifyExtends(_delegate);
75+
}
76+
77+
/// List of [MultiFactorInfo] which represents the available
78+
/// second factors that can be used to complete the sign-in for the current session.
79+
List<MultiFactorInfo> get hints => _delegate.hints;
80+
81+
/// A MultiFactorSession, an opaque session identifier for the current sign-in flow.
82+
MultiFactorSession get session => _delegate.session;
83+
84+
/// Completes sign in with a second factor using an MultiFactorAssertion which
85+
/// confirms that the user has successfully completed the second factor challenge.
86+
Future<UserCredential> resolveSignIn(
87+
MultiFactorAssertion assertion,
88+
) async {
89+
final credential = await _delegate.resolveSignIn(assertion._delegate);
90+
return UserCredential._(_auth, credential);
91+
}
92+
}
93+
94+
/// MultiFactor exception related to Firebase Authentication. Check the error code
95+
/// and message for more details.
96+
class FirebaseAuthMultiFactorException extends FirebaseAuthException {
97+
final FirebaseAuth _auth;
98+
final FirebaseAuthMultiFactorExceptionPlatform _delegate;
99+
100+
FirebaseAuthMultiFactorException._(this._auth, this._delegate)
101+
: super(
102+
code: _delegate.code,
103+
message: _delegate.message,
104+
email: _delegate.email,
105+
credential: _delegate.credential,
106+
phoneNumber: _delegate.phoneNumber,
107+
tenantId: _delegate.tenantId,
108+
);
109+
110+
MultiFactorResolver get resolver =>
111+
MultiFactorResolver._(_auth, _delegate.resolver);
112+
}

packages/firebase_auth/firebase_auth_platform_interface/lib/src/firebase_auth_multi_factor_exception.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ import 'package:meta/meta.dart';
88

99
/// MultiFactor exception related to Firebase Authentication. Check the error code
1010
/// and message for more details.
11-
class FirebaseAuthMultiFactorException extends FirebaseAuthException
11+
class FirebaseAuthMultiFactorExceptionPlatform extends FirebaseAuthException
1212
implements Exception {
1313
// ignore: public_member_api_docs
1414
@protected
15-
FirebaseAuthMultiFactorException({
15+
FirebaseAuthMultiFactorExceptionPlatform({
1616
String? message,
1717
required String code,
1818
String? email,

packages/firebase_auth/firebase_auth_platform_interface/lib/src/method_channel/utils/exception.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ FirebaseException platformExceptionToFirebaseAuthException(
7474
);
7575
}
7676

77-
FirebaseAuthMultiFactorException parseMultiFactorError(
77+
FirebaseAuthMultiFactorExceptionPlatform parseMultiFactorError(
7878
Map<String, Object?> details) {
7979
final code = details['code'] as String?;
8080
final message = details['message'] as String?;
@@ -124,7 +124,7 @@ FirebaseAuthMultiFactorException parseMultiFactorError(
124124
auth,
125125
);
126126

127-
return FirebaseAuthMultiFactorException(
127+
return FirebaseAuthMultiFactorExceptionPlatform(
128128
code: code ?? 'Unknown',
129129
message: message,
130130
resolver: multiFactorResolver,

packages/firebase_auth/firebase_auth_platform_interface/lib/src/platform_interface/platform_interface_multi_factor.dart

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,20 +56,39 @@ class MultiFactorSession {
5656
final String id;
5757
}
5858

59+
/// {@template .multiFactorAssertion}
5960
/// Represents an assertion that the Firebase Authentication server
6061
/// can use to authenticate a user as part of a multi-factor flow.
61-
class MultiFactorAssertionPlatform {}
62+
/// {@endtemplate}
63+
class MultiFactorAssertionPlatform extends PlatformInterface {
64+
/// {@macro .multiFactorAssertion}
65+
MultiFactorAssertionPlatform() : super(token: _token);
66+
67+
static final Object _token = Object();
68+
69+
/// Ensures that any delegate class has extended a [MultiFactorResolverPlatform].
70+
static void verifyExtends(MultiFactorAssertionPlatform instance) {
71+
PlatformInterface.verifyToken(instance, _token);
72+
}
73+
}
6274

63-
/// {@macro .platformInterfaceMultiFactorResolverPlatform}
75+
/// {@template .platformInterfaceMultiFactorResolverPlatform}
6476
/// Utility class that contains methods to resolve second factor
6577
/// requirements on users that have opted into two-factor authentication.
6678
/// {@endtemplate}
67-
class MultiFactorResolverPlatform {
79+
class MultiFactorResolverPlatform extends PlatformInterface {
6880
/// {@macro .platformInterfaceMultiFactorResolverPlatform}
69-
const MultiFactorResolverPlatform(
81+
MultiFactorResolverPlatform(
7082
this.hints,
7183
this.session,
72-
);
84+
) : super(token: _token);
85+
86+
static final Object _token = Object();
87+
88+
/// Ensures that any delegate class has extended a [MultiFactorResolverPlatform].
89+
static void verifyExtends(MultiFactorResolverPlatform instance) {
90+
PlatformInterface.verifyToken(instance, _token);
91+
}
7392

7493
/// List of [MultiFactorInfo] which represents the available
7594
/// second factors that can be used to complete the sign-in for the current session.

packages/firebase_auth/firebase_auth_web/lib/src/utils/web_utils.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ FirebaseAuthException getFirebaseAuthException(
5050
firebaseError as auth_interop.MultiFactorError,
5151
);
5252

53-
return FirebaseAuthMultiFactorException(
53+
return FirebaseAuthMultiFactorExceptionPlatform(
5454
code: code,
5555
message: message,
5656
email: firebaseError.email,

0 commit comments

Comments
 (0)