Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
2ed35fe
Implementing ConfirmWithWebOTP Method
Evanition Jul 25, 2023
060c42a
Update API reports
Evanition Jul 25, 2023
bfbc747
changed firebase error to custom error messages
AngelAngelXie Jul 25, 2023
3508d6e
Update API reports
AngelAngelXie Jul 25, 2023
2f3416c
Implementing verifyPhoneNumber method
Evanition Jul 25, 2023
dc6df46
Update API reports
Evanition Jul 25, 2023
b6af0af
added overloaded signInWithPhoneNumber
AngelAngelXie Jul 25, 2023
73185ec
overloading verifyPhoneNumber
Evanition Jul 25, 2023
58fdc57
Update API reports
Evanition Jul 25, 2023
bc82fe5
adding changes to demo app
Evanition Jul 26, 2023
7004408
adding webOTPError Type
Evanition Jul 26, 2023
a24db79
added unit tests & fixed documentations
AngelAngelXie Jul 27, 2023
341dd90
Update API reports
AngelAngelXie Jul 27, 2023
456fa58
formatted code
AngelAngelXie Jul 27, 2023
00ee945
removed unnecessary imports
AngelAngelXie Jul 27, 2023
137e657
fixed demo app & modified errors
AngelAngelXie Jul 27, 2023
41eec76
added documentation & fixed the fallback code
AngelAngelXie Jul 28, 2023
89420d6
fixed error message
AngelAngelXie Jul 28, 2023
7d954a5
Revert "added unit tests & fixed documentations"
AngelAngelXie Jul 28, 2023
b9de8ab
attempt to fix totp integration test errors
AngelAngelXie Jul 28, 2023
520ac96
attempt to fix totp integration test
AngelAngelXie Jul 28, 2023
29abe5c
editted demo app for web otp fallback handling
AngelAngelXie Jul 28, 2023
99fc534
fixing errors
AngelAngelXie Jul 31, 2023
18bf34f
clean up existing code
AngelAngelXie Aug 1, 2023
ca40b4b
added unit tests for signInWithPhoneNumber
AngelAngelXie Aug 1, 2023
4a9196d
attempt to resolve error
AngelAngelXie Aug 1, 2023
0d69efa
removed test changes
AngelAngelXie Aug 2, 2023
3845e1e
modifying rollup to resolve sourcemap warning
AngelAngelXie Aug 2, 2023
1e8e2c8
changed webOTPTimeoutname
AngelAngelXie Aug 7, 2023
cec3a97
cleaning up code
AngelAngelXie Aug 7, 2023
ff232d0
Reverted irrelevant changes
AngelAngelXie Aug 7, 2023
82d6bfe
cleaning up code
AngelAngelXie Aug 7, 2023
c17f2db
cleaning up code
AngelAngelXie Aug 7, 2023
a5a5d65
reverting un-needed changes
AngelAngelXie Aug 7, 2023
196c8dc
removing unecessary elements
Evanition Aug 9, 2023
4869aa7
Merge branch 'WebOTP' into DewayneTest3
AngelAngelXie Aug 10, 2023
abe3ea2
Linting and formatting
Evanition Aug 10, 2023
4c4eda6
modified unit tests
Evanition Aug 10, 2023
de47f1d
fixing unit test
Evanition Aug 11, 2023
d73e42b
added unit tests
AngelAngelXie Aug 11, 2023
1088ecf
removed unneeded imports
AngelAngelXie Aug 11, 2023
34ce322
fixing unit tests
AngelAngelXie Aug 11, 2023
e510234
fixed format
AngelAngelXie Aug 11, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions common/api-review/auth.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ export const AuthErrorCodes: {
readonly MISSING_RECAPTCHA_VERSION: "auth/missing-recaptcha-version";
readonly INVALID_RECAPTCHA_VERSION: "auth/invalid-recaptcha-version";
readonly INVALID_REQ_TYPE: "auth/invalid-req-type";
readonly WEB_OTP_NOT_RETRIEVED: "auth/web-otp-not-retrieved";
};

// @public
Expand Down Expand Up @@ -281,6 +282,7 @@ export interface Config {
// @public
export interface ConfirmationResult {
confirm(verificationCode: string): Promise<UserCredential>;
confirmWithWebOTP(auth: Auth, webOTPTimeoutSeconds: number): Promise<UserCredential | undefined>;
readonly verificationId: string;
}

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

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

// @public
export function signInWithPhoneNumber(auth: Auth, phoneNumber: string, appVerifier: ApplicationVerifier, webOTPTimeoutSeconds: number): Promise<UserCredential>;

// @public
export function signInWithPopup(auth: Auth, provider: AuthProvider, resolver?: PopupRedirectResolver): Promise<UserCredential>;

Expand Down
22 changes: 22 additions & 0 deletions docs-devsite/auth.confirmationresult.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export interface ConfirmationResult
| Method | Description |
| --- | --- |
| [confirm(verificationCode)](./auth.confirmationresult.md#confirmationresultconfirm) | Finishes a phone number sign-in, link, or reauthentication. |
| [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. |

## ConfirmationResult.verificationId

Expand Down Expand Up @@ -72,3 +73,24 @@ const userCredential = await confirmationResult.confirm(verificationCode);
```

## ConfirmationResult.confirmWithWebOTP()

Automatically fetches a verification code from an SMS message. Then, calls (<!-- -->@<!-- -->link confirm(verificationCode)<!-- -->} to finish a phone number sign-in, link, or reauthentication.

<b>Signature:</b>

```typescript
confirmWithWebOTP(auth: Auth, webOTPTimeoutSeconds: number): Promise<UserCredential | undefined>;
```

### Parameters

| Parameter | Type | Description |
| --- | --- | --- |
| auth | [Auth](./auth.auth.md#auth_interface) | the current [Auth](./auth.auth.md#auth_interface) instance |
| webOTPTimeoutSeconds | number | Error would be thrown if WebOTP does not resolve within this specified timeout parameter (in seconds). |

<b>Returns:</b>

Promise&lt;[UserCredential](./auth.usercredential.md#usercredential_interface) \| undefined&gt;

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

```

## signInWithPhoneNumber()

Asynchronously signs in using a phone number.

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.

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.

This method does not work in a Node.js environment.

<b>Signature:</b>

```typescript
export declare function signInWithPhoneNumber(auth: Auth, phoneNumber: string, appVerifier: ApplicationVerifier, webOTPTimeoutSeconds: number): Promise<UserCredential>;
```

### Parameters

| Parameter | Type | Description |
| --- | --- | --- |
| auth | [Auth](./auth.auth.md#auth_interface) | The [Auth](./auth.auth.md#auth_interface) instance. |
| phoneNumber | string | The user's phone number in E.164 format (e.g. +16505550101). |
| appVerifier | [ApplicationVerifier](./auth.applicationverifier.md#applicationverifier_interface) | The [ApplicationVerifier](./auth.applicationverifier.md#applicationverifier_interface)<!-- -->. |
| webOTPTimeoutSeconds | number | |

<b>Returns:</b>

Promise&lt;[UserCredential](./auth.usercredential.md#usercredential_interface)<!-- -->&gt;

### Example


```javascript
// 'recaptcha-container' is the ID of an element in the DOM.
const applicationVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container');
const userCredential = await signInWithPhoneNumber(auth, phoneNumber, applicationVerifier, 10);

```

## signInWithPopup()

Authenticates a Firebase client using a popup-based OAuth authentication flow.
Expand Down Expand Up @@ -1899,6 +1939,7 @@ AUTH_ERROR_CODES_MAP_DO_NOT_USE_INTERNALLY: {
readonly MISSING_RECAPTCHA_VERSION: "auth/missing-recaptcha-version";
readonly INVALID_RECAPTCHA_VERSION: "auth/invalid-recaptcha-version";
readonly INVALID_REQ_TYPE: "auth/invalid-req-type";
readonly WEB_OTP_NOT_RETRIEVED: "auth/web-otp-not-retrieved";
}
```

Expand Down
49 changes: 46 additions & 3 deletions docs-devsite/auth.phoneauthprovider.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,11 @@ export declare class PhoneAuthProvider

| Method | Modifiers | Description |
| --- | --- | --- |
| [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. |
| [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. |
| [credentialFromError(error)](./auth.phoneauthprovider.md#phoneauthprovidercredentialfromerror) | <code>static</code> | Returns an [AuthCredential](./auth.authcredential.md#authcredential_class) when passed an error. |
| [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)<!-- -->. |
| [verifyPhoneNumber(phoneOptions, applicationVerifier)](./auth.phoneauthprovider.md#phoneauthproviderverifyphonenumber) | | Starts a phone number authentication flow by sending a verification code to the given phone number. |
| [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. |

## PhoneAuthProvider.(constructor)

Expand Down Expand Up @@ -91,7 +92,7 @@ readonly providerId: "phone";

## PhoneAuthProvider.credential()

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.
Creates a phone auth credential, given the verification ID from and the code that was sent to the user's mobile device.

<b>Signature:</b>

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

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

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

```

## PhoneAuthProvider.verifyPhoneNumber()

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.

<b>Signature:</b>

```typescript
verifyPhoneNumber(phoneOptions: PhoneInfoOptions | string, applicationVerifier: ApplicationVerifier, webOTPTimeoutSeconds: number): Promise<UserCredential>;
```

### Parameters

| Parameter | Type | Description |
| --- | --- | --- |
| phoneOptions | [PhoneInfoOptions](./auth.md#phoneinfooptions) \| string | |
| 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)<!-- -->. |
| webOTPTimeoutSeconds | number | Error would be thrown if WebOTP does not resolve within this specified timeout parameter (in seconds). |

<b>Returns:</b>

Promise&lt;[UserCredential](./auth.usercredential.md#usercredential_interface)<!-- -->&gt;

A Promise for a UserCredential.

### Example 1


```javascript
const provider = new PhoneAuthProvider(auth);
const userCredential = await provider.verifyPhoneNumber(phoneNumber, applicationVerifier, 10);

```

### Example 2

An alternative flow is provided using the `signInWithPhoneNumber` method.

```javascript
const userCredential = signInWithPhoneNumber(auth, phoneNumber, applicationVerifier, 10);

```

### Example


Expand Down
27 changes: 15 additions & 12 deletions packages/auth/demo/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ import {
browserPopupRedirectResolver,
connectAuthEmulator,
initializeRecaptchaConfig,
signInWithPhoneNumber,
AuthErrorCodes,
validatePassword
} from '@firebase/auth';

Expand Down Expand Up @@ -118,6 +120,7 @@ const providersIcons = {
* Returns active user (currentUser or lastUser).
* @return {!firebase.User}
*/

function activeUser() {
const type = $('input[name=toggle-user-selection]:checked').val();
if (type === 'lastUser') {
Expand Down Expand Up @@ -711,25 +714,25 @@ function clearApplicationVerifier() {
/**
* Sends a phone number verification code for sign-in.
*/
function onSignInVerifyPhoneNumber() {
async function onSignInVerifyPhoneNumber() {
const phoneNumber = $('#signin-phone-number').val();
const provider = new PhoneAuthProvider(auth);
// Clear existing reCAPTCHA as an existing reCAPTCHA could be targeted for a
// link/re-auth operation.
clearApplicationVerifier();
// Initialize a reCAPTCHA application verifier.
makeApplicationVerifier('signin-verify-phone-number');
provider.verifyPhoneNumber(phoneNumber, applicationVerifier).then(
verificationId => {
clearApplicationVerifier();
$('#signin-phone-verification-id').val(verificationId);
alertSuccess('Phone verification sent!');
},
error => {
await signInWithPhoneNumber(auth, phoneNumber, applicationVerifier, 30)
.then(userCredential => {
onAuthUserCredentialSuccess(userCredential);
})
.catch(e => {
clearApplicationVerifier();
onAuthError(error);
}
);
onAuthError(e);
if (e.code === `auth/${AuthErrorCodes.WEB_OTP_NOT_RETRIEVED}`) {
const verificationCode = $('#signin-phone-verification-code').val();
e.confirmationResult.confirm(verificationCode);
}
});
}

/**
Expand Down
26 changes: 21 additions & 5 deletions packages/auth/src/core/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,8 @@
* limitations under the License.
*/

import { AuthErrorMap, User } from '../model/public_types';
import { ErrorFactory, ErrorMap } from '@firebase/util';

import { AuthErrorMap, User, ConfirmationResult } from '../model/public_types';
import { ErrorFactory, ErrorMap, FirebaseError } from '@firebase/util';
import { IdTokenMfaResponse } from '../api/authentication/mfa';
import { AppName } from '../model/auth';
import { AuthCredential } from './credentials';
Expand Down Expand Up @@ -133,6 +132,7 @@ export const enum AuthErrorCode {
MISSING_RECAPTCHA_VERSION = 'missing-recaptcha-version',
INVALID_RECAPTCHA_VERSION = 'invalid-recaptcha-version',
INVALID_REQ_TYPE = 'invalid-req-type',
WEB_OTP_NOT_RETRIEVED = 'web-otp-not-retrieved',
UNSUPPORTED_PASSWORD_POLICY_SCHEMA_VERSION = 'unsupported-password-policy-schema-version',
PASSWORD_DOES_NOT_MEET_REQUIREMENTS = 'password-does-not-meet-requirements'
}
Expand Down Expand Up @@ -383,7 +383,18 @@ function _debugErrorMap(): ErrorMap<AuthErrorCode> {
'The reCAPTCHA version is missing when sending request to the backend.',
[AuthErrorCode.INVALID_REQ_TYPE]: 'Invalid request parameters.',
[AuthErrorCode.INVALID_RECAPTCHA_VERSION]:
'The reCAPTCHA version is invalid when sending request to the backend.',
'The reCAPTCHA version sent to the backend is invalid.',
[AuthErrorCode.WEB_OTP_NOT_RETRIEVED]:
'Web OTP code is not retrieved successfully',
/**
* This is the default error message.
* This message is customized to one of the following depending on the type of error:
* `Web OTP code is not fetched before timeout`
* `The auto-retrieved credential or code is not defined`
* `Web OTP get method failed to retrieve the code`
* `Web OTP code received is incorrect`
* `Web OTP is not supported`
*/
[AuthErrorCode.UNSUPPORTED_PASSWORD_POLICY_SCHEMA_VERSION]:
'The password policy received from the backend uses a schema version that is not supported by this version of the Firebase SDK.',
[AuthErrorCode.PASSWORD_DOES_NOT_MEET_REQUIREMENTS]:
Expand Down Expand Up @@ -434,6 +445,10 @@ export interface NamedErrorParams {
user?: User;
_serverResponse?: object;
}
export interface WebOTPError extends FirebaseError {
code: AuthErrorCode.WEB_OTP_NOT_RETRIEVED;
confirmationResult: ConfirmationResult; // Standard ConfirmationResult; for fallback
}

/**
* @internal
Expand Down Expand Up @@ -597,5 +612,6 @@ export const AUTH_ERROR_CODES_MAP_DO_NOT_USE_INTERNALLY = {
MISSING_CLIENT_TYPE: 'auth/missing-client-type',
MISSING_RECAPTCHA_VERSION: 'auth/missing-recaptcha-version',
INVALID_RECAPTCHA_VERSION: 'auth/invalid-recaptcha-version',
INVALID_REQ_TYPE: 'auth/invalid-req-type'
INVALID_REQ_TYPE: 'auth/invalid-req-type',
WEB_OTP_NOT_RETRIEVED: 'auth/web-otp-not-retrieved'
} as const;
13 changes: 13 additions & 0 deletions packages/auth/src/model/public_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,19 @@ export interface ConfirmationResult {
* @param verificationCode - The code that was sent to the user's mobile device.
*/
confirm(verificationCode: string): Promise<UserCredential>;
/**
*
* Automatically fetches a verification code from an SMS message. Then, calls
* (@link confirm(verificationCode)} to finish a phone number sign-in, link, or reauthentication.
*
* @param auth - the current {@link Auth} instance
* @param webOTPTimeoutSeconds - Error would be thrown if WebOTP does not resolve within this specified timeout parameter (in seconds).
*
*/
confirmWithWebOTP(
auth: Auth,
webOTPTimeoutSeconds: number
): Promise<UserCredential | undefined>;
}

/**
Expand Down
Loading