Skip to content

Commit b4773dc

Browse files
committed
feat(android): add support for Firebase Phone Number Verification (PNV)
fix reviews
1 parent f5b932a commit b4773dc

3 files changed

Lines changed: 80 additions & 28 deletions

File tree

docs/phone-number-verification/usage/index.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ The method returns an array with one entry per SIM slot. Each entry includes:
7272
- `isSupported` — whether PNV is available for this SIM.
7373
- `simSlot` — the SIM slot index (0-based).
7474
- `carrierId` — the carrier identifier string.
75-
- `reason` — a `VerificationSupportStatus` string explaining why the SIM is or isn't supported.
75+
- `reason` — a {@link VerificationSupportStatus} string explaining why the SIM is or isn't supported.
7676

7777
### Query a specific SIM slot
7878

packages/phone-number-verification/lib/modular.ts

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,21 @@
1818
import { Platform } from 'react-native';
1919
import { getReactNativeModule } from '@react-native-firebase/app/dist/module/internal/nativeModule';
2020

21-
import type { VerificationSupportInfo, VerifiedPhoneNumberResult } from './types/pnv';
21+
import type { VerificationSupportResult, VerifiedPhoneNumberTokenResult } from './types/pnv';
2222

2323
const UNSUPPORTED_MSG = 'Firebase Phone Number Verification is only supported on Android.';
2424

2525
const NATIVE_MODULE_NAME = 'RNFBPnvModule';
2626

2727
interface NativePnvModule {
2828
enableTestSession(token: string): Promise<void>;
29-
getVerificationSupportInfo(): Promise<VerificationSupportInfo[]>;
30-
getVerificationSupportInfoForSimSlot(simSlot: number): Promise<VerificationSupportInfo[]>;
31-
getVerifiedPhoneNumber(): Promise<VerifiedPhoneNumberResult>;
29+
getVerificationSupportInfo(): Promise<VerificationSupportResult[]>;
30+
getVerificationSupportInfoForSimSlot(simSlot: number): Promise<VerificationSupportResult[]>;
31+
getVerifiedPhoneNumber(): Promise<VerifiedPhoneNumberTokenResult>;
3232
getDigitalCredentialPayload(nonce: string): Promise<string>;
33-
exchangeCredentialResponseForPhoneNumber(dcApiResponse: string): Promise<VerifiedPhoneNumberResult>;
33+
exchangeCredentialResponseForPhoneNumber(
34+
dcApiResponse: string,
35+
): Promise<VerifiedPhoneNumberTokenResult>;
3436
}
3537

3638
function getNativeModule(): NativePnvModule {
@@ -49,11 +51,17 @@ function getNativeModule(): NativePnvModule {
4951
/**
5052
* Enables a test session for SIM-less testing.
5153
* Must be called only once per app instance; subsequent calls will reject with
52-
* error code `test-session-already-enabled`.
54+
* error code `pnv/test-session-already-enabled`.
5355
*
56+
* @remarks
5457
* In test mode, phone numbers follow the format: valid country code followed by all zeros.
58+
* Requires a test token generated from the Firebase Console (7-day TTL).
5559
*
5660
* @param token - The test token generated from the Firebase Console.
61+
* @throws `pnv/test-session-already-enabled` if called more than once.
62+
* @throws `pnv/invalid-test-number-id` if the token is empty, expired, or duplicated.
63+
* @see https://firebase.google.com/docs/phone-number-verification
64+
* @android
5765
*/
5866
export function enableTestSession(token: string): Promise<void> {
5967
return getNativeModule().enableTestSession(token);
@@ -62,10 +70,18 @@ export function enableTestSession(token: string): Promise<void> {
6270
/**
6371
* Checks if the device's SIM card(s) support phone number verification.
6472
*
65-
* @param simSlot - Optional SIM slot index to query a specific slot instead of all slots.
66-
* @returns Array of support info results, one per SIM slot (or one entry if simSlot is specified).
73+
* @remarks
74+
* This method does not require user consent and can be called freely.
75+
* Returns one {@link VerificationSupportResult} per SIM slot (or one entry if `simSlot` is specified).
76+
*
77+
* @param simSlot - Optional 0-based SIM slot index to query a specific slot instead of all slots.
78+
* @returns Array of support results, one per SIM slot.
79+
* @see https://firebase.google.com/docs/phone-number-verification
80+
* @android
6781
*/
68-
export function getVerificationSupportInfo(simSlot?: number): Promise<VerificationSupportInfo[]> {
82+
export function getVerificationSupportInfo(
83+
simSlot?: number,
84+
): Promise<VerificationSupportResult[]> {
6985
if (simSlot !== undefined) {
7086
return getNativeModule().getVerificationSupportInfoForSimSlot(simSlot);
7187
}
@@ -76,9 +92,16 @@ export function getVerificationSupportInfo(simSlot?: number): Promise<Verificati
7692
* Initiates the phone number verification flow, including user consent and token generation.
7793
* A consent dialog will be presented to the user.
7894
*
95+
* @remarks
96+
* The app should prepare the user for the consent screen before calling this method.
97+
*
7998
* @returns The verified phone number and a JWT token with full claims for server-side validation.
99+
* @throws `pnv/carrier-not-supported` if the carrier does not support PNV.
100+
* @throws `pnv/activity-context-required` if no foreground Activity is available.
101+
* @see https://firebase.google.com/docs/phone-number-verification/android/get-started
102+
* @android
80103
*/
81-
export function getVerifiedPhoneNumber(): Promise<VerifiedPhoneNumberResult> {
104+
export function getVerifiedPhoneNumber(): Promise<VerifiedPhoneNumberTokenResult> {
82105
return getNativeModule().getVerifiedPhoneNumber();
83106
}
84107

@@ -88,6 +111,8 @@ export function getVerifiedPhoneNumber(): Promise<VerifiedPhoneNumberResult> {
88111
*
89112
* @param nonce - A unique value to prevent replay attacks.
90113
* @returns The digital credential payload string.
114+
* @see https://firebase.google.com/docs/phone-number-verification
115+
* @android
91116
*/
92117
export function getDigitalCredentialPayload(nonce: string): Promise<string> {
93118
return getNativeModule().getDigitalCredentialPayload(nonce);
@@ -99,9 +124,12 @@ export function getDigitalCredentialPayload(nonce: string): Promise<string> {
99124
*
100125
* @param dcApiResponse - The JWT from the Credential Manager response.
101126
* @returns The verified phone number and a JWT token with full claims for server-side validation.
127+
* @throws `pnv/invalid-digital-credential-response` if the response is invalid.
128+
* @see https://firebase.google.com/docs/phone-number-verification
129+
* @android
102130
*/
103131
export function exchangeCredentialResponseForPhoneNumber(
104132
dcApiResponse: string,
105-
): Promise<VerifiedPhoneNumberResult> {
133+
): Promise<VerifiedPhoneNumberTokenResult> {
106134
return getNativeModule().exchangeCredentialResponseForPhoneNumber(dcApiResponse);
107135
}

packages/phone-number-verification/lib/types/pnv.ts

Lines changed: 40 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@
1818
/**
1919
* Status indicating why a SIM slot does or does not support phone number verification.
2020
* Maps to the native `VerificationSupportStatus` IntDef constants.
21+
*
22+
* @remarks
23+
* Returned as the {@link VerificationSupportResult.reason} field. Use this to determine
24+
* whether to fall back to an alternative verification method (e.g. SMS).
25+
*
26+
* @see https://firebase.google.com/docs/phone-number-verification
27+
* @public
2128
*/
2229
export type VerificationSupportStatus =
2330
| 'CAPABILITY_STATUS_UNSPECIFIED'
@@ -28,40 +35,57 @@ export type VerificationSupportStatus =
2835

2936
/**
3037
* Result describing whether a specific SIM slot supports phone number verification.
38+
*
39+
* @remarks
40+
* Mirrors the native `com.google.firebase.pnv.VerificationSupportResult` class.
41+
* One instance is returned per SIM slot when calling {@link getVerificationSupportInfo}.
42+
*
43+
* @see https://firebase.google.com/docs/phone-number-verification
44+
* @public
3145
*/
32-
export interface VerificationSupportInfo {
46+
export interface VerificationSupportResult {
3347
/** Whether this SIM slot supports phone number verification. */
34-
isSupported: boolean;
48+
readonly isSupported: boolean;
3549
/** The SIM slot index (0-based). */
36-
simSlot: number;
50+
readonly simSlot: number;
3751
/** The carrier identifier string for this SIM slot. */
38-
carrierId: string;
52+
readonly carrierId: string;
3953
/** The detailed reason for the support status. */
40-
reason: VerificationSupportStatus;
54+
readonly reason: VerificationSupportStatus;
4155
}
4256

4357
/**
4458
* Result of a successful phone number verification, containing the verified
4559
* phone number and a JWT token for server-side validation.
60+
*
61+
* @remarks
62+
* Mirrors the native `com.google.firebase.pnv.VerifiedPhoneNumberTokenResult` class.
63+
* Returned by {@link getVerifiedPhoneNumber} and {@link exchangeCredentialResponseForPhoneNumber}.
64+
*
65+
* @see https://firebase.google.com/docs/phone-number-verification
66+
* @public
4667
*/
47-
export interface VerifiedPhoneNumberResult {
48-
/** The verified phone number (E.164 format). */
49-
phoneNumber: string;
68+
export interface VerifiedPhoneNumberTokenResult {
69+
/** The verified phone number in E.164 format. */
70+
readonly phoneNumber: string;
5071
/** The raw JWT token string for server-side validation. */
51-
token: string;
72+
readonly token: string;
5273
/** Token expiration time as Unix epoch seconds. */
53-
expirationTimestamp: number;
74+
readonly expirationTimestamp: number;
5475
/** Token issued-at time as Unix epoch seconds. */
55-
issuedAtTimestamp: number;
56-
/** The nonce from the JWT payload, or null if not present. */
57-
nonce: string | null;
58-
/** All JWT claims as a key-value map, or null if unavailable. */
59-
claims: Record<string, unknown> | null;
76+
readonly issuedAtTimestamp: number;
77+
/** The nonce from the JWT payload, or `null` if not present. */
78+
readonly nonce: string | null;
79+
/** All JWT claims as a key-value map, or `null` if unavailable. */
80+
readonly claims: Record<string, unknown> | null;
6081
}
6182

6283
/**
6384
* Error codes returned by the Firebase Phone Number Verification SDK.
64-
* These map to `FirebasePnvStatusCodes` constants.
85+
* These map to `FirebasePnvStatusCodes` constants from the native SDK.
86+
*
87+
* @see https://firebase.google.com/docs/phone-number-verification
88+
* @public
6589
*/
6690
export type PnvErrorCode =
6791
| 'pnv/carrier-not-supported'

0 commit comments

Comments
 (0)