-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(auth): Add multi-factor support for the sign-in flow (#6593)
* feat(auth): adds iOS/Web support for multi-factor sign-in flow Adds code required to complete the sign-in flow for users that have enrolled second factors. Due to a difference in the implementation of the PhoneAuthProvider it is not possible to follow the implementation of the Web API. * docs(auth): update documentation for multi-factor authentication Provide general setup and usage information for multi-factor authentication flows. * fix(docs): Change prev link for Firestore docs to multi-factor auth * feat(auth): Adds Android support for multi-factor sign-in flow Implement the Android part required to support the multi-factor sign-in flow. Makes the `multiFactor` property for the Firebase user object available as well. Known issues: - The enrollmentInfo for a MultiFactorInfo is currently reported with 0 on Android. * feat(auth): multi-factor enroll feature for Android and e2e-tests * feat(auth): Implement multi-factor enrollment for iOS * fix(tests): More robust matchers for invalid-verification-code error * Fix error message for invalid phone numbers to match the error message produced by the Web. * Add test and fix error message for unknown multi-factor hint to match the error message produced by the Web.
- Loading branch information
Showing
18 changed files
with
1,621 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
--- | ||
title: Multi-factor Auth | ||
description: Increase security by adding Multi-factor authentication to your app. | ||
next: /firestore/usage | ||
previous: /auth/phone-auth | ||
--- | ||
|
||
# iOS Setup | ||
|
||
Make sure to follow [the official Identity Platform | ||
documentation](https://cloud.google.com/identity-platform/docs/ios/mfa#enabling_multi-factor_authentication) | ||
to enable multi-factor authentication for your project and verify your app. | ||
|
||
# Enroll a new factor | ||
|
||
> Before a user can enroll a second factor they need to verify their email. See | ||
> [`User`](/reference/auth/user#sendEmailVerification) interface is returned. | ||
Begin by obtaining a [`MultiFactorUser`](/reference/auth/multifactoruser) | ||
instance for the current user. This is the entry point for most multi-factor | ||
operations: | ||
|
||
```js | ||
import auth from '@react-native-firebase/auth'; | ||
const multiFactorUser = await auth.multiFactor(auth()); | ||
``` | ||
|
||
Request the session identifier and use the phone number obtained from the user | ||
to send a verification code: | ||
|
||
```js | ||
const session = await multiFactorUser.getSession(); | ||
const phoneOptions = { | ||
phoneNumber, | ||
session, | ||
}; | ||
|
||
// Sends a text message to the user | ||
const verificationId = await auth().verifyPhoneNumberForMultiFactor(phoneOptions); | ||
``` | ||
|
||
Once the user has provided the verification code received by text message, you | ||
can complete the process: | ||
|
||
```js | ||
const cred = auth.PhoneAuthProvider.credential(verificationId, verificationCode); | ||
const multiFactorAssertion = auth.PhoneMultiFactorGenerator.assertion(cred); | ||
await multiFactorUser.enroll(multiFactorAssertion, 'Optional display name for the user); | ||
``` | ||
You can inspect [`User#multiFactor`](/reference/auth/user#multiFactor) for | ||
information about the user's enrolled factors. | ||
|
||
# Sign-in flow using multi-factor | ||
|
||
Ensure the account has already enrolled a second factor. Begin by calling the | ||
default sign-in methods, for example email and password. If the account requires | ||
a second factor to complete login, an exception will be raised: | ||
|
||
```js | ||
import auth from '@react-native-firebase/auth'; | ||
auth() | ||
.signInWithEmailAndPassword(email, password) | ||
.then(() => { | ||
// User has not enrolled a second factor | ||
}) | ||
.catch(error => { | ||
const { code } = error; | ||
// Make sure to check if multi factor authentication is required | ||
if (code === 'auth/multi-factor-auth-required') { | ||
return; | ||
} | ||
// Other error | ||
}); | ||
``` | ||
|
||
Using the error object you can obtain a | ||
[`MultiFactorResolver`](/reference/auth/multifactorresolver) instance and | ||
continue the flow: | ||
|
||
```js | ||
const resolver = auth.getMultiFactorResolver(auth(), error); | ||
``` | ||
|
||
The resolver object has all the required information to prompt the user for a | ||
specific factor: | ||
|
||
```js | ||
if (resolver.hints.length > 1) { | ||
// Use resolver.hints to display a list of second factors to the user | ||
} | ||
// Currently only phone based factors are supported | ||
if (resolver.hints[0].factorId === auth.PhoneMultiFactorGenerator.FACTOR_ID) { | ||
// Continue with the sign-in flow | ||
} | ||
``` | ||
|
||
Using a multi-factor hint and the session information you can send a | ||
verification code to the user: | ||
|
||
```js | ||
const hint = resolver.hints[0]; | ||
const sessionId = resolver.session; | ||
auth() | ||
.verifyPhoneNumberWithMultiFactorInfo(hint, sessionId) // triggers the message to the user | ||
.then(verificationId => setVerificationId(verificationId)); | ||
``` | ||
|
||
Once the user has entered the verification code you can create a multi-factor | ||
assertion and finish the flow: | ||
|
||
```js | ||
const credential = auth.PhoneAuthProvider.credential(verificationId, verificationCode); | ||
const multiFactorAssertion = auth.PhoneMultiFactorGenerator.assertion(credential); | ||
resolver.resolveSignIn(multiFactorAssertion).then(userCredential => { | ||
// additionally onAuthStateChanged will be triggered as well | ||
}); | ||
``` | ||
|
||
Upon successful sign-in, any | ||
[`onAuthStateChanged`](/auth/usage#listening-to-authentication-state) listeners | ||
will trigger with the new authentication state of the user. | ||
|
||
To put the example together: | ||
|
||
```js | ||
import auth from '@react-native-firebase/auth'; | ||
const authInstance = auth(); | ||
authInstance | ||
.signInWithEmailAndPassword(email, password) | ||
.then(() => { | ||
// User has not enrolled a second factor | ||
}) | ||
.catch(error => { | ||
const { code } = error; | ||
// Make sure to check if multi factor authentication is required | ||
if (code !== 'auth/multi-factor-auth-required') { | ||
const resolver = auth.getMultiFactorResolver(authInstance, error); | ||
if (resolver.hints.length > 1) { | ||
// Use resolver.hints to display a list of second factors to the user | ||
} | ||
// Currently only phone based factors are supported | ||
if (resolver.hints[0].factorId === auth.PhoneMultiFactorGenerator.FACTOR_ID) { | ||
const hint = resolver.hints[0]; | ||
const sessionId = resolver.session; | ||
authInstance | ||
.verifyPhoneNumberWithMultiFactorInfo(hint, sessionId) // triggers the message to the user | ||
.then(verificationId => setVerificationId(verificationId)); | ||
// Request verificationCode from user | ||
const credential = auth.PhoneAuthProvider.credential(verificationId, verificationCode); | ||
const multiFactorAssertion = auth.PhoneMultiFactorGenerator.assertion(credential); | ||
resolver.resolveSignIn(multiFactorAssertion).then(userCredential => { | ||
// additionally onAuthStateChanged will be triggered as well | ||
}); | ||
} | ||
} | ||
}); | ||
``` | ||
|
||
# Testing | ||
|
||
You can define test phone numbers and corresponding verification codes. The | ||
official[official | ||
guide](https://cloud.google.com/identity-platform/docs/ios/mfa#enabling_multi-factor_authentication) | ||
contains more information on setting this up. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
3c64bf5
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs:
react-native-firebase – ./
react-native-firebase.vercel.app
react-native-firebase-git-main-invertase.vercel.app
rnfirebase.io
react-native-firebase-invertase.vercel.app