Skip to content

Commit 03c6862

Browse files
authored
Merge e510234 into 43e402f
2 parents 43e402f + e510234 commit 03c6862

File tree

10 files changed

+740
-41
lines changed

10 files changed

+740
-41
lines changed

common/api-review/auth.api.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ export const AuthErrorCodes: {
235235
readonly MISSING_RECAPTCHA_VERSION: "auth/missing-recaptcha-version";
236236
readonly INVALID_RECAPTCHA_VERSION: "auth/invalid-recaptcha-version";
237237
readonly INVALID_REQ_TYPE: "auth/invalid-req-type";
238+
readonly WEB_OTP_NOT_RETRIEVED: "auth/web-otp-not-retrieved";
238239
};
239240

240241
// @public
@@ -281,6 +282,7 @@ export interface Config {
281282
// @public
282283
export interface ConfirmationResult {
283284
confirm(verificationCode: string): Promise<UserCredential>;
285+
confirmWithWebOTP(auth: Auth, webOTPTimeoutSeconds: number): Promise<UserCredential | undefined>;
284286
readonly verificationId: string;
285287
}
286288

@@ -625,6 +627,7 @@ export class PhoneAuthProvider {
625627
static readonly PROVIDER_ID: 'phone';
626628
readonly providerId: "phone";
627629
verifyPhoneNumber(phoneOptions: PhoneInfoOptions | string, applicationVerifier: ApplicationVerifier): Promise<string>;
630+
verifyPhoneNumber(phoneOptions: PhoneInfoOptions | string, applicationVerifier: ApplicationVerifier, webOTPTimeoutSeconds: number): Promise<UserCredential>;
628631
}
629632

630633
// @public
@@ -776,6 +779,9 @@ export function signInWithEmailLink(auth: Auth, email: string, emailLink?: strin
776779
// @public
777780
export function signInWithPhoneNumber(auth: Auth, phoneNumber: string, appVerifier: ApplicationVerifier): Promise<ConfirmationResult>;
778781

782+
// @public
783+
export function signInWithPhoneNumber(auth: Auth, phoneNumber: string, appVerifier: ApplicationVerifier, webOTPTimeoutSeconds: number): Promise<UserCredential>;
784+
779785
// @public
780786
export function signInWithPopup(auth: Auth, provider: AuthProvider, resolver?: PopupRedirectResolver): Promise<UserCredential>;
781787

docs-devsite/auth.confirmationresult.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export interface ConfirmationResult
2929
| Method | Description |
3030
| --- | --- |
3131
| [confirm(verificationCode)](./auth.confirmationresult.md#confirmationresultconfirm) | Finishes a phone number sign-in, link, or reauthentication. |
32+
| [confirmWithWebOTP(auth, webOTPTimeoutSeconds)](./auth.confirmationresult.md#confirmationresultconfirmwithwebotp) | Automatically fetches a verification code from an SMS message. Then, calls (<!-- -->@<!-- -->link confirm(verificationCode)<!-- -->} to finish a phone number sign-in, link, or reauthentication. |
3233

3334
## ConfirmationResult.verificationId
3435

@@ -72,3 +73,24 @@ const userCredential = await confirmationResult.confirm(verificationCode);
7273
7374
```
7475

76+
## ConfirmationResult.confirmWithWebOTP()
77+
78+
Automatically fetches a verification code from an SMS message. Then, calls (<!-- -->@<!-- -->link confirm(verificationCode)<!-- -->} to finish a phone number sign-in, link, or reauthentication.
79+
80+
<b>Signature:</b>
81+
82+
```typescript
83+
confirmWithWebOTP(auth: Auth, webOTPTimeoutSeconds: number): Promise<UserCredential | undefined>;
84+
```
85+
86+
### Parameters
87+
88+
| Parameter | Type | Description |
89+
| --- | --- | --- |
90+
| auth | [Auth](./auth.auth.md#auth_interface) | the current [Auth](./auth.auth.md#auth_interface) instance |
91+
| webOTPTimeoutSeconds | number | Error would be thrown if WebOTP does not resolve within this specified timeout parameter (in seconds). |
92+
93+
<b>Returns:</b>
94+
95+
Promise&lt;[UserCredential](./auth.usercredential.md#usercredential_interface) \| undefined&gt;
96+

docs-devsite/auth.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ Firebase Authentication
4444
| [signInWithEmailAndPassword(auth, email, password)](./auth.md#signinwithemailandpassword) | Asynchronously signs in using an email and password. |
4545
| [signInWithEmailLink(auth, email, emailLink)](./auth.md#signinwithemaillink) | Asynchronously signs in using an email and sign-in email link. |
4646
| [signInWithPhoneNumber(auth, phoneNumber, appVerifier)](./auth.md#signinwithphonenumber) | Asynchronously signs in using a phone number. |
47+
| [signInWithPhoneNumber(auth, phoneNumber, appVerifier, webOTPTimeoutSeconds)](./auth.md#signinwithphonenumber) | Asynchronously signs in using a phone number. |
4748
| [signInWithPopup(auth, provider, resolver)](./auth.md#signinwithpopup) | Authenticates a Firebase client using a popup-based OAuth authentication flow. |
4849
| [signInWithRedirect(auth, provider, resolver)](./auth.md#signinwithredirect) | Authenticates a Firebase client using a full-page redirect flow. |
4950
| [signOut(auth)](./auth.md#signout) | Signs out the current user. |
@@ -917,6 +918,45 @@ const credential = await confirmationResult.confirm(verificationCode);
917918

918919
```
919920

921+
## signInWithPhoneNumber()
922+
923+
Asynchronously signs in using a phone number.
924+
925+
This method sends a code via SMS to the given phone number. Then, the method will try to autofill the SMS code for the user and sign the user in. A [UserCredential](./auth.usercredential.md#usercredential_interface) is then returned if the process is successful. If the process failed, is thrown.
926+
927+
For abuse prevention, this method also requires a [ApplicationVerifier](./auth.applicationverifier.md#applicationverifier_interface)<!-- -->. This SDK includes a reCAPTCHA-based implementation, [RecaptchaVerifier](./auth.recaptchaverifier.md#recaptchaverifier_class)<!-- -->. This function can work on other platforms that do not support the [RecaptchaVerifier](./auth.recaptchaverifier.md#recaptchaverifier_class) (like React Native), but you need to use a third-party [ApplicationVerifier](./auth.applicationverifier.md#applicationverifier_interface) implementation.
928+
929+
This method does not work in a Node.js environment.
930+
931+
<b>Signature:</b>
932+
933+
```typescript
934+
export declare function signInWithPhoneNumber(auth: Auth, phoneNumber: string, appVerifier: ApplicationVerifier, webOTPTimeoutSeconds: number): Promise<UserCredential>;
935+
```
936+
937+
### Parameters
938+
939+
| Parameter | Type | Description |
940+
| --- | --- | --- |
941+
| auth | [Auth](./auth.auth.md#auth_interface) | The [Auth](./auth.auth.md#auth_interface) instance. |
942+
| phoneNumber | string | The user's phone number in E.164 format (e.g. +16505550101). |
943+
| appVerifier | [ApplicationVerifier](./auth.applicationverifier.md#applicationverifier_interface) | The [ApplicationVerifier](./auth.applicationverifier.md#applicationverifier_interface)<!-- -->. |
944+
| webOTPTimeoutSeconds | number | |
945+
946+
<b>Returns:</b>
947+
948+
Promise&lt;[UserCredential](./auth.usercredential.md#usercredential_interface)<!-- -->&gt;
949+
950+
### Example
951+
952+
953+
```javascript
954+
// 'recaptcha-container' is the ID of an element in the DOM.
955+
const applicationVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container');
956+
const userCredential = await signInWithPhoneNumber(auth, phoneNumber, applicationVerifier, 10);
957+
958+
```
959+
920960
## signInWithPopup()
921961

922962
Authenticates a Firebase client using a popup-based OAuth authentication flow.
@@ -1899,6 +1939,7 @@ AUTH_ERROR_CODES_MAP_DO_NOT_USE_INTERNALLY: {
18991939
readonly MISSING_RECAPTCHA_VERSION: "auth/missing-recaptcha-version";
19001940
readonly INVALID_RECAPTCHA_VERSION: "auth/invalid-recaptcha-version";
19011941
readonly INVALID_REQ_TYPE: "auth/invalid-req-type";
1942+
readonly WEB_OTP_NOT_RETRIEVED: "auth/web-otp-not-retrieved";
19021943
}
19031944
```
19041945

docs-devsite/auth.phoneauthprovider.md

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,11 @@ export declare class PhoneAuthProvider
3838

3939
| Method | Modifiers | Description |
4040
| --- | --- | --- |
41-
| [credential(verificationId, verificationCode)](./auth.phoneauthprovider.md#phoneauthprovidercredential) | <code>static</code> | Creates a phone auth credential, given the verification ID from [PhoneAuthProvider.verifyPhoneNumber()](./auth.phoneauthprovider.md#phoneauthproviderverifyphonenumber) and the code that was sent to the user's mobile device. |
41+
| [credential(verificationId, verificationCode)](./auth.phoneauthprovider.md#phoneauthprovidercredential) | <code>static</code> | Creates a phone auth credential, given the verification ID from and the code that was sent to the user's mobile device. |
4242
| [credentialFromError(error)](./auth.phoneauthprovider.md#phoneauthprovidercredentialfromerror) | <code>static</code> | Returns an [AuthCredential](./auth.authcredential.md#authcredential_class) when passed an error. |
4343
| [credentialFromResult(userCredential)](./auth.phoneauthprovider.md#phoneauthprovidercredentialfromresult) | <code>static</code> | Generates an [AuthCredential](./auth.authcredential.md#authcredential_class) from a [UserCredential](./auth.usercredential.md#usercredential_interface)<!-- -->. |
4444
| [verifyPhoneNumber(phoneOptions, applicationVerifier)](./auth.phoneauthprovider.md#phoneauthproviderverifyphonenumber) | | Starts a phone number authentication flow by sending a verification code to the given phone number. |
45+
| [verifyPhoneNumber(phoneOptions, applicationVerifier, webOTPTimeoutSeconds)](./auth.phoneauthprovider.md#phoneauthproviderverifyphonenumber) | | Completes the phone number authentication flow by sending a verification code to the given phone number, automatically retrieving the verification code from the SMS message, and signing the user in. |
4546

4647
## PhoneAuthProvider.(constructor)
4748

@@ -91,7 +92,7 @@ readonly providerId: "phone";
9192

9293
## PhoneAuthProvider.credential()
9394

94-
Creates a phone auth credential, given the verification ID from [PhoneAuthProvider.verifyPhoneNumber()](./auth.phoneauthprovider.md#phoneauthproviderverifyphonenumber) and the code that was sent to the user's mobile device.
95+
Creates a phone auth credential, given the verification ID from and the code that was sent to the user's mobile device.
9596

9697
<b>Signature:</b>
9798

@@ -103,7 +104,7 @@ static credential(verificationId: string, verificationCode: string): PhoneAuthCr
103104

104105
| Parameter | Type | Description |
105106
| --- | --- | --- |
106-
| verificationId | string | The verification ID returned from [PhoneAuthProvider.verifyPhoneNumber()](./auth.phoneauthprovider.md#phoneauthproviderverifyphonenumber)<!-- -->. |
107+
| verificationId | string | The verification ID returned from . |
107108
| verificationCode | string | The verification code sent to the user's mobile device. |
108109

109110
<b>Returns:</b>
@@ -242,6 +243,48 @@ const userCredential = confirmationResult.confirm(verificationCode);
242243

243244
```
244245

246+
## PhoneAuthProvider.verifyPhoneNumber()
247+
248+
Completes the phone number authentication flow by sending a verification code to the given phone number, automatically retrieving the verification code from the SMS message, and signing the user in.
249+
250+
<b>Signature:</b>
251+
252+
```typescript
253+
verifyPhoneNumber(phoneOptions: PhoneInfoOptions | string, applicationVerifier: ApplicationVerifier, webOTPTimeoutSeconds: number): Promise<UserCredential>;
254+
```
255+
256+
### Parameters
257+
258+
| Parameter | Type | Description |
259+
| --- | --- | --- |
260+
| phoneOptions | [PhoneInfoOptions](./auth.md#phoneinfooptions) \| string | |
261+
| applicationVerifier | [ApplicationVerifier](./auth.applicationverifier.md#applicationverifier_interface) | For abuse prevention, this method also requires a [ApplicationVerifier](./auth.applicationverifier.md#applicationverifier_interface)<!-- -->. This SDK includes a reCAPTCHA-based implementation, [RecaptchaVerifier](./auth.recaptchaverifier.md#recaptchaverifier_class)<!-- -->. |
262+
| webOTPTimeoutSeconds | number | Error would be thrown if WebOTP does not resolve within this specified timeout parameter (in seconds). |
263+
264+
<b>Returns:</b>
265+
266+
Promise&lt;[UserCredential](./auth.usercredential.md#usercredential_interface)<!-- -->&gt;
267+
268+
A Promise for a UserCredential.
269+
270+
### Example 1
271+
272+
273+
```javascript
274+
const provider = new PhoneAuthProvider(auth);
275+
const userCredential = await provider.verifyPhoneNumber(phoneNumber, applicationVerifier, 10);
276+
277+
```
278+
279+
### Example 2
280+
281+
An alternative flow is provided using the `signInWithPhoneNumber` method.
282+
283+
```javascript
284+
const userCredential = signInWithPhoneNumber(auth, phoneNumber, applicationVerifier, 10);
285+
286+
```
287+
245288
### Example
246289

247290

packages/auth/demo/src/index.js

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ import {
7373
browserPopupRedirectResolver,
7474
connectAuthEmulator,
7575
initializeRecaptchaConfig,
76+
signInWithPhoneNumber,
77+
AuthErrorCodes,
7678
validatePassword
7779
} from '@firebase/auth';
7880

@@ -118,6 +120,7 @@ const providersIcons = {
118120
* Returns active user (currentUser or lastUser).
119121
* @return {!firebase.User}
120122
*/
123+
121124
function activeUser() {
122125
const type = $('input[name=toggle-user-selection]:checked').val();
123126
if (type === 'lastUser') {
@@ -711,25 +714,25 @@ function clearApplicationVerifier() {
711714
/**
712715
* Sends a phone number verification code for sign-in.
713716
*/
714-
function onSignInVerifyPhoneNumber() {
717+
async function onSignInVerifyPhoneNumber() {
715718
const phoneNumber = $('#signin-phone-number').val();
716-
const provider = new PhoneAuthProvider(auth);
717719
// Clear existing reCAPTCHA as an existing reCAPTCHA could be targeted for a
718720
// link/re-auth operation.
719721
clearApplicationVerifier();
720722
// Initialize a reCAPTCHA application verifier.
721723
makeApplicationVerifier('signin-verify-phone-number');
722-
provider.verifyPhoneNumber(phoneNumber, applicationVerifier).then(
723-
verificationId => {
724-
clearApplicationVerifier();
725-
$('#signin-phone-verification-id').val(verificationId);
726-
alertSuccess('Phone verification sent!');
727-
},
728-
error => {
724+
await signInWithPhoneNumber(auth, phoneNumber, applicationVerifier, 30)
725+
.then(userCredential => {
726+
onAuthUserCredentialSuccess(userCredential);
727+
})
728+
.catch(e => {
729729
clearApplicationVerifier();
730-
onAuthError(error);
731-
}
732-
);
730+
onAuthError(e);
731+
if (e.code === `auth/${AuthErrorCodes.WEB_OTP_NOT_RETRIEVED}`) {
732+
const verificationCode = $('#signin-phone-verification-code').val();
733+
e.confirmationResult.confirm(verificationCode);
734+
}
735+
});
733736
}
734737

735738
/**

packages/auth/src/core/errors.ts

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,8 @@
1515
* limitations under the License.
1616
*/
1717

18-
import { AuthErrorMap, User } from '../model/public_types';
19-
import { ErrorFactory, ErrorMap } from '@firebase/util';
20-
18+
import { AuthErrorMap, User, ConfirmationResult } from '../model/public_types';
19+
import { ErrorFactory, ErrorMap, FirebaseError } from '@firebase/util';
2120
import { IdTokenMfaResponse } from '../api/authentication/mfa';
2221
import { AppName } from '../model/auth';
2322
import { AuthCredential } from './credentials';
@@ -133,6 +132,7 @@ export const enum AuthErrorCode {
133132
MISSING_RECAPTCHA_VERSION = 'missing-recaptcha-version',
134133
INVALID_RECAPTCHA_VERSION = 'invalid-recaptcha-version',
135134
INVALID_REQ_TYPE = 'invalid-req-type',
135+
WEB_OTP_NOT_RETRIEVED = 'web-otp-not-retrieved',
136136
UNSUPPORTED_PASSWORD_POLICY_SCHEMA_VERSION = 'unsupported-password-policy-schema-version',
137137
PASSWORD_DOES_NOT_MEET_REQUIREMENTS = 'password-does-not-meet-requirements'
138138
}
@@ -383,7 +383,18 @@ function _debugErrorMap(): ErrorMap<AuthErrorCode> {
383383
'The reCAPTCHA version is missing when sending request to the backend.',
384384
[AuthErrorCode.INVALID_REQ_TYPE]: 'Invalid request parameters.',
385385
[AuthErrorCode.INVALID_RECAPTCHA_VERSION]:
386-
'The reCAPTCHA version is invalid when sending request to the backend.',
386+
'The reCAPTCHA version sent to the backend is invalid.',
387+
[AuthErrorCode.WEB_OTP_NOT_RETRIEVED]:
388+
'Web OTP code is not retrieved successfully',
389+
/**
390+
* This is the default error message.
391+
* This message is customized to one of the following depending on the type of error:
392+
* `Web OTP code is not fetched before timeout`
393+
* `The auto-retrieved credential or code is not defined`
394+
* `Web OTP get method failed to retrieve the code`
395+
* `Web OTP code received is incorrect`
396+
* `Web OTP is not supported`
397+
*/
387398
[AuthErrorCode.UNSUPPORTED_PASSWORD_POLICY_SCHEMA_VERSION]:
388399
'The password policy received from the backend uses a schema version that is not supported by this version of the Firebase SDK.',
389400
[AuthErrorCode.PASSWORD_DOES_NOT_MEET_REQUIREMENTS]:
@@ -434,6 +445,10 @@ export interface NamedErrorParams {
434445
user?: User;
435446
_serverResponse?: object;
436447
}
448+
export interface WebOTPError extends FirebaseError {
449+
code: AuthErrorCode.WEB_OTP_NOT_RETRIEVED;
450+
confirmationResult: ConfirmationResult; // Standard ConfirmationResult; for fallback
451+
}
437452

438453
/**
439454
* @internal
@@ -597,5 +612,6 @@ export const AUTH_ERROR_CODES_MAP_DO_NOT_USE_INTERNALLY = {
597612
MISSING_CLIENT_TYPE: 'auth/missing-client-type',
598613
MISSING_RECAPTCHA_VERSION: 'auth/missing-recaptcha-version',
599614
INVALID_RECAPTCHA_VERSION: 'auth/invalid-recaptcha-version',
600-
INVALID_REQ_TYPE: 'auth/invalid-req-type'
615+
INVALID_REQ_TYPE: 'auth/invalid-req-type',
616+
WEB_OTP_NOT_RETRIEVED: 'auth/web-otp-not-retrieved'
601617
} as const;

packages/auth/src/model/public_types.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,19 @@ export interface ConfirmationResult {
587587
* @param verificationCode - The code that was sent to the user's mobile device.
588588
*/
589589
confirm(verificationCode: string): Promise<UserCredential>;
590+
/**
591+
*
592+
* Automatically fetches a verification code from an SMS message. Then, calls
593+
* (@link confirm(verificationCode)} to finish a phone number sign-in, link, or reauthentication.
594+
*
595+
* @param auth - the current {@link Auth} instance
596+
* @param webOTPTimeoutSeconds - Error would be thrown if WebOTP does not resolve within this specified timeout parameter (in seconds).
597+
*
598+
*/
599+
confirmWithWebOTP(
600+
auth: Auth,
601+
webOTPTimeoutSeconds: number
602+
): Promise<UserCredential | undefined>;
590603
}
591604

592605
/**

0 commit comments

Comments
 (0)