FPNV 技術電信業者新手上路指南

上次修改日期:2025 年 9 月 10 日

總覽

本文件涵蓋透過 TS.43 電話號碼驗證,將電信業者加入 Firebase 電話號碼驗證 (FPNV) 的所有必要步驟。

術語

相關當事人

  • CSP:通訊服務供應商
    • 例如:行動電信業者
  • 集結網站
    • 應用程式端匯總器:匯總器可讓應用程式執行驗證,不必直接與電信業者互動
    • 例如 Firebase 電話號碼驗證
    • 中繼集結網站:支援電信業者加入應用程式集結網站的集結網站
      • 元聚合器可負責為電信業者設定授權伺服器,以及/或向面向應用程式的聚合器設定授權伺服器的詳細資料
  • FPNV:Firebase 電話號碼驗證
  • Google 客戶技術顧問:協助電信業者加入 FPNV 的 Google 客戶技術顧問
  • Android Telephony:提供 Android 上的電話號碼 API,包括供電信業者和匯總器提供 TS.43 驗證的平台
  • GSMA:行動網路業者協會,負責定義規格,包括 TS.43
  • CAMARA:Linux 開放原始碼專案,與 GSMA 合作定義電信業者 API

驗證條款

  • PNV:電話號碼驗證
  • TS.43:定義行動用戶端和伺服器與電信業者通訊時使用的 HTTP 通訊協定
  • EAP-AKA:在 https://www.rfc-editor.org/rfc/rfc4187 中定義的驗證方法,不需要與使用者互動
  • ECS:授權設定伺服器
    • 聚合器與貨運公司溝通的入口點
  • ODSA:裝置端服務啟用
    • 指 ECS 提供的不同作業,可啟用裝置上的服務
    • 例如:AcquireTemporaryToken、GetPhoneNumber

電信業者授權伺服器和 PNV 端點

建立必要端點

動作 1:電信業者實作下列端點,這些端點都可透過網際網路存取。如要進一步瞭解實作方式,請參閱附錄 A

技術規定

一般效能:所有端點的正常運作時間至少應為 99.99%。

安全性:基於安全考量,電信業者端點必須符合下列規定:

  • EAP-AKA 驗證權杖:必須在 1 小時內失效
  • 臨時權杖:只能使用一次,5 分鐘後失效
  • 選項 1 - Vanilla TS.43
    • OAuth 權杖:必須在 1 小時內失效
  • 選項 2 - CAMARA
    • CAMARA 存取權杖:單次使用,5 分鐘後失效

API 資料品質:成功回應的內容 100% 準確 (即 MSISDN 應正確無誤)。

FPNV 支援兩種 TS.43 規格。主要差異在於 FPNV 伺服器與電信業者交換 TempToken 的方式。

選項 1 - Vanilla TS.43 實作

Android 裝置提出的要求

  1. EAP-AKA 端點:傳回授權權杖
  2. AcquireTemporaryToken 端點:提供驗證權杖,傳回 TempToken

來自 FPNV 伺服器的要求

  1. OAuth 2.0 端點 - OAuth 用戶端 ID/密鑰流程:提供 OAuth 用戶端 ID/密鑰,傳回 OAuth 存取權杖
  2. GetPhoneNumber 端點:提供 OAuth 存取權杖和 TempToken,傳回對應的電話號碼

選項 2 - 導入 CAMARA

CAMARA 實作方式與原始 TS.43 實作方式類似,但處理 FPNV 伺服器要求的端點除外。

Android 裝置提出的要求

  1. EAP-AKA 端點:傳回授權權杖
  2. AcquireTemporaryToken 端點:提供驗證權杖,傳回 TempToken

來自 FPNV 伺服器的要求

  1. OAuth 2.0 端點 - JWT 持有者流程:提供含有 TempToken 的 JWT,傳回 CAMARA 存取權杖
  2. CAMARA NumberVerification v2 端點:提供 CAMARA 存取權杖,傳回對應的電話號碼

加入 Android 電話通訊和 FPNV

電信業者測試應用程式

步驟 2:電信業者與 Google 技術客戶經理 (TAM) 聯絡,TAM 會將 FPNV 電信業者測試應用程式提供給電信業者。這個電信業者測試應用程式會模擬 FPNV 傳送的要求,但不會涉及 FPNV 伺服器。電信業者可使用這款測試應用程式,驗證端點是否正常運作。

動作 3:電信業者使用 FPNV 電信業者測試應用程式,驗證上述端點是否能正常運作。

設定必要的正式版設定

Android Config - EAP-AKA / AcquireTempToken

ACTION4:電信業者為 Android Telephony 的 EAP-AKA/AcquireTempToken 請求定義生產設定

  • 設定:
    • 這個電信業者的 Android 標準電信業者 ID
    • TS.43 use_cases 值:use_case=GetPhoneNumber
    • EAP-AKA/AcquireTempToken 的正式版授權伺服器網址
    • Firebase 生產環境 x509 憑證的 SAN 和指紋
    • SANfpnv.googleapis.com
    • 指紋aad068c93399a22fc2b11ab58468e8cb72b8f9fc53700991799a8b764c589c7e

Firebase 設定 - 將 TempToken 換成電話

ACTION5:Firebase 憑證,用於從電信業者擷取 OAuth 權杖

  • Vanilla TS.43
    • 電信業者會為 FPNV 的要求建立 OAuth 用戶端 ID 和密鑰。電信業者接著會設定 OAuth 端點,針對這些憑證傳回存取權杖
  • CAMARA
    • Google TAM 提供 Google 的公開金鑰,因此電信業者的 OAuth 端點可以驗證 JWT 是否由 Google 簽署

步驟 6:電信業者定義 FPNV 伺服器的正式版設定,以便將 TempToken 換成手機

  • 這個 MNO 的 Android 標準電信業者 ID
  • Vanilla TS.43
    • OAuth - 用戶端 ID/密鑰流程
    • OAuth 端點網址
    • OAuth 用戶端 ID/密鑰
    • OAuth 範圍 (如有)
    • GetPhoneNumber
    • GetPhoneNumber 端點網址
  • CAMARA
    • OAuth - JWT 持有者流程
    • OAuth 端點網址
    • NumberVerification API v2
    • NumberVerification 端點網址

共用憑證/設定

Firebase 電話號碼驗證

步驟 7:電信業者與 Google 技術帳戶管理員分享步驟 4步驟 6 的生產設定。

  • [重要] 請務必使用安全的頻外 (不透過電子郵件、文件等)機制,與 Google 分享 OAuth 密鑰。這項頻外機制將由電信業者和 Google 技術支援帳戶經理 (TAM) 共同決定。

步驟 8:Google TAM 會使用電信業者測試應用程式,驗證設定是否能正常運作。驗證完成後,Google TAM 會將 OAuth 憑證儲存在 Google 安全儲存空間,並更新 FPNV 的設定,將 TempToken 換成電話 (即步驟 6 的設定)。

Android 電話

行動 9:電信業者按照「Google Open Gateway CSP Onboarding」文件 (Google TAM 會提供給電信業者) 操作。電信業者或 Google TAM 會提交 Buganizer 票證,以便加入 Android Telephony 的設定: https://issuetracker.google.com/issues/new?component=1861595&template=2168610。 這個錯誤會從 ACTION4 取得正式版設定。

如果中繼聚合器代表電視網設定 FPNV 整合,則必須提供電視網領導階層 (總監以上) 的同意聲明 (電子郵件、PDF、信件等),確認與該營運商的業務關係。之後,中繼匯總器可以代表電信業者,向 Android Telephony 提供電信業者的設定。

附件 A。詳細實作方式

區分大小寫

  • HTTP 標頭「不」區分大小寫
  • 不過,XML 和 JSON 格式會區分大小寫。因此,請確保要求/回應欄位與這份說明文件完全相符。

步驟 1 - EAP-AKA / AcquireTempToken

這張圖表顯示裝置執行 EAP-AKA 和 AcquireTempToken,從電信業者伺服器擷取臨時權杖。
圖 1. 裝置會執行 EAP-AKA,然後執行 AcquireTempToken,從電信業者伺服器擷取 TempToken。步驟 2 - 將 TempToken 換成電話號碼 將說明如何將 TempToken 換成電話號碼。

端點:EAP-AKA 和 AcquireTempToken 必須使用相同的 ECS 端點。

EAP-AKA 驗證

參考資料TS.43 v12.0 - Section 2.8.1 -「Embedded EAP-AKA Authentication by Entitlement Configuration Server」(透過授權設定伺服器進行內嵌 EAP-AKA 驗證)。

EAP-AKA 步驟 1 - 驗證挑戰
EAP-AKA #1 - GET 要求傳送至 ECS

Android Telephony 模組會將 TS.43 EAP-AKA 要求傳送至電信業者的授權伺服器。

Android 的要求標頭

  • Acceptapplication/vnd.gsma.eap-relay.v1.0+json
    • 這是 GSMA 專用的 JSON 格式,不只是 application/json

Android 的要求欄位

  • eap_id:請參閱 RCC.14 附錄 C
    • 0<IMSI>@<realm>.mnc<MNC>.mcc<MCC>.3gppnetwork.org
  • GID1:只有在授權版本為 12.0 時才會指定
  • app_name:編碼後的 AppName 會包含執行電話號碼驗證的用途 MD5 雜湊值:
    • 所有面向應用程式的聚合器要求都會有 Google-OGI 的應用程式名稱
  • app:應用程式 ID ap2014 代表電話號碼資訊
  • terminal_vendor/model/sw_version:設為任意值;Android 不保證這些欄位包含實際裝置資訊
  • vers:設定版本,例如 0 或 1
  • entitlement_version:Google 會根據電信業者要求設定傳送給電信業者的授權版本
    • 通常 entitlement_version 為 10.0 或 12.0
EAP-AKA #1 - ECS 的回應

ECS 回應標頭

  • Content-Type:Android 預期回應類型會與要求中的 Accept 標頭相符
    • application/vnd.gsma.eap-relay.v1.0+json

ECS 回應欄位

EAP-AKA 步驟 2 - 取得驗證權杖
EAP-AKA #2 - POST 要求傳送至 ECS

Android Telephony 模組隨後會將收到的 eap-relay-packet 傳回同一個端點。

Android 的要求標頭

  • Accept:Android 會設定兩個 Accept 標頭:
    • application/vnd.gsma.eap-relay.v1.0+json:如果裝置需要再次傳送 EAP-AKA 要求,是指電信業者再次傳回 JSON
    • text/vnd.wap.connectivity-xml:指 Android 預期電信業者傳回 EAP-AKA 驗證權杖的實際格式
  • Content-Typeapplication/vnd.gsma.eap-relay.v1.0+json

Android 的要求欄位

  • eap-relay-packet:包含先前的 EAP-AKA 回應的 eap-relay-packet,但格式為 EAP-Response/AKA-Challenge,遵循 RFC 4817 - 第 9.2 節
EAP-AKA #2 - ECS 的回覆

EAP-AKA 驗證成功後,電信業者會傳回驗證權杖。

ECS 回應標頭

  • Content-Type:Android 預期回應會與要求 Accept 標頭相符
    • 也就是說,Android 預期含有授權權杖的回應類型為 text/vnd.wap.connectivity-xml
    • 另一個 Accept 標頭 application/vnd.gsma.eap-relay.v1.0+json 則用於電信業者希望 Android 執行另一個 EAP-AKA 要求的情況

ECS 回應欄位

  • TOKEN.token:包含驗證權杖
  • TOKEN.validity:裝置收到回應後,回應有效的秒數

AcquireTemporary Token

AcquireTempToken - 對 ECS 發出 GET 要求

Android 用戶端會使用從 EAP-AKA 收到的驗證權杖,呼叫電信業者的 AcquireTemporaryToken 端點,擷取臨時權杖。要求

  • 範例TS.43 v12.0 - Section 6.4.6 - 「AcquireTemporaryToken Request Example」(取得臨時權杖要求範例)
  • AcquireTempToken 的參數與 EAP-AKA #1 類似,但有以下例外狀況:
    • AcquireTempToken 也會指定 IMSI, operationoperation_targets
    • AcquireTempToken 未指定 EAP_ID

Android 的要求標頭

  • Accept:Android 會設定 text/vnd.wap.connectivity-xml

Android 的要求欄位

  • terminal_vendor/model/sw_version:Android 無法保證這些欄位包含裝置的實際資訊
  • operation_targets
    • FPNV:作業目標為 GetPhoneNumber

AcquireTempToken - ECS 的回應

範例TS.43 v12.0 - Section 6.6.6 - "AcquireTemporaryToken Response Example"

ECS 回應標頭

  • Content-Type:Android 預期回應類型會與要求中的 Accept 標頭相符
    • text/vnd.wap.connectivity-xml

ECS 回應欄位

  • APPLICATION.TemporaryToken:FPNV 伺服器可交換電話號碼的 TemporaryToken
  • APPLICATION.TemporaryTokenExpiry:到期時間,格式為 YYYY-MM-DDThh:mm:ssTZD
    • Google 會驗證 TempToken 的到期時間是否符合技術要求
  • APPLICATION.OperationResult:請參閱 TS.43 v12.0 - Section 6.5.1
    • 具體來說,如果作業是 SUCCESS,則傳回 1

步驟 2 - 換取電話號碼的 TempToken

選項 1 - Vanilla TS.43

這張圖表顯示 Google 伺服器如何使用 Vanilla TS.43,向電信業者交換臨時權杖,取得已驗證的電話號碼。
圖 2a. 接著,Google 伺服器會呼叫 GetPhoneNumber,將 TempToken 傳遞給電信業者,換取已驗證的電話號碼。這張圖表會抽象化「步驟 1 - EAP-AKA / AcquireTempToken」

端點:OAuth 和 GetPhoneNumber 端點可以是不同的伺服器/端點。這些端點也可能與 EAP-AKA/AcquireTempToken 端點不同。

OAuth

電信業者應按照這份 OAuth 指南操作,並向 Google 提供必要的 OAuth 資訊 (用戶端 ID、用戶端密鑰、OAuth 伺服器 URL)。

OAuth - 對電信業者驗證伺服器提出 POST 要求

FPNV 要求標頭

  • Authorization:FPNV 會設定 Basic $BASE64_ENCODED_CREDENTIALS
    • 採用 Base64 編碼的憑證是 OAuth 的 Base64 編碼 $CLIENT_ID:$CLIENT_SECRET
  • Content-Type:FPNV 會設定 application/x-www-form-urlencoded
  • Accept:FPNV 會設定 application/json

FPNV 要求欄位

  • grant_typeclient_credentials
POST HTTP/1.1
Host: $OAUTH_ENDPOINT
Authorization: Basic $BASE64_ENCODED_CREDENTIALS
Content-Type: application/x-www-form-urlencoded
Accept: application/json

grant_type=client_credentials
OAuth - 電信業者驗證伺服器的回應

電信業者的回應標頭

  • Content-Type:FPNV 預期回應類型會與要求中的 Accept 標頭相符
    • application/json

電信業者的回應欄位

  • access_token:OAuth 存取權杖
  • token_typebearer
  • expires_in:OAuth 存取權杖的到期時間 (以秒為單位)
    • Google 會驗證 OAuth 權杖的到期時間是否符合技術規定
200 OK
Content-Type: application/json

{
  "access_token": $ACCESS_TOKEN,
  "token_type": "bearer",
  "expires_in": $EXPIRATION_IN_SECS,
}
GetPhoneNumber
GetPhoneNumber - 對 ECS 提出 POST 要求

Google 驗證伺服器會使用 GetPhoneNumber 作業擷取電話號碼。

FPNV 的要求標頭

  • Acceptapplication/json
  • Content-Typeapplication/json

FPNV 的要求欄位

  • requestor_id:識別呼叫 GetPhoneNumber TS.43 作業的服務
    • Firebase 電話號碼驗證 UUID191fd7cc-f7cd-4bb4-a5d2-455ae1fb9a19
  • temporary_token:從 AcquireTempToken 取得的 TemporaryToken
  • access_token:Google 用於向電信業者驗證的 OAuth 權杖
  • terminal_vendor/model/sw_version:FPNV 會以任意值填入這些欄位
  • entitlement_version:Google 會根據電信業者要求設定傳送給電信業者的授權版本
    • 通常 entitlement_version 為 10.0 或 12.0
  • app:FPNV 會設定 ap2014
  • app_name:FPNV 會為所有 FPNV 要求設定 firebase
    • 注意:無論使用哪個匯總工具,AcquireTempToken 的 app_name 都會是 Google-OGI
  • operation:FPNV 會設定 GetPhoneNumber
GetPhoneNumber - ECS 的回應

範例TS.43 v12.0 - Section 6.6.7 - "GetPhoneNumber Response Example"

電信業者的回應標頭

  • Content-Type:FPNV 預期回應類型會與要求中的 Accept 標頭相符
    • application/json

電信業者的回應欄位

  • ap2014.MSISDN:FPNV 預期電話號碼會以 E164 格式傳回
    • JSON 區分大小寫,因此 MSISDN 必須大寫
TemporaryToken 錯誤代碼

參照 TS.43 v12.0 第 2.8.6 節。

下表詳細說明 ECS 預期會針對 GetPhoneNumber 要求傳回給 Google 驗證伺服器的失敗回應:

情境

從 ECS 取得 GET/POST 回應代碼

第三方伺服器動作

要求中的參數無效或遺漏,或格式有誤

400 錯誤的要求

在下次叫用使用者時重試 / 在用戶端重新啟動後重試

要求中的臨時權杖無效或已過期

401 未獲授權

盡可能觸發裝置從 ECS 取得 (新的) 有效臨時權杖

與臨時權杖搭配使用時,作業無效

403 Forbidden

在下次叫用使用者時重試 / 在用戶端重新啟動後重試

找不到要求的資源

找不到 404

在下次叫用使用者時重試 / 在用戶端重新啟動後重試

ECS 在處理要求時發生內部錯誤

500 內部伺服器錯誤

在下次叫用使用者時重試 / 在用戶端重新啟動後重試

選項 2 - CAMARA

這張圖顯示 Google 伺服器使用 CAMARA 的 JWT 持有人流程,向電信業者交換臨時權杖以取得已驗證的電話號碼。
圖 2b. 接著,Google 伺服器會執行 CAMARA 的 JWT 持有人流程,將 TempToken 傳送給電信業者,換取已驗證的電話號碼。這張圖表會抽象化「步驟 1 - EAP-AKA / AcquireTempToken」

端點:擷取 CAMARA 存取權杖和擷取電話號碼可能使用不同的伺服器/端點。這些端點也可能與 EAP-AKA / AcquireTempToken 端點不同。

OAuth - 擷取 CAMARA 存取權杖

Google 只會支援 CAMARA 的 JWT 持有人流程支援 CIBA 流程。

CAMARA 存取權杖 - 向電信業者發出 POST 要求

Google 會建立含有下列欄位的 JWT。

  • iss:JWT 的簽發者 (又稱用戶端 ID)
    • firebase (實際 FPNV 整合) 或 fpnv-carrier-tester-app (電信業者測試應用程式)
  • sub:JWT 的主體
    • operatortoken:$TEMP_TOKEN
  • aud:對象;JWT 的預期收件者
    • 權杖端點網址 (即授權伺服器的網址)
  • exp:到期時間 (以秒為單位)
    • Google 會傳送與 CAMARA 存取權杖有效期限相符的到期時間 (請參閱技術需求)
  • iat:發行時間 (以秒為單位)
  • jti:專屬 ID,可避免重播攻擊
    • 例如隨機產生的 UUID
  • scope:要求目的
    • dpv:FraudPreventionAndDetection number-verification:device-phone-number:read
{
  "iss": "firebase",
  "sub": "operatortoken:ey...",
  "aud": $OAUTH_ENDPOINT,
  "exp": $EXPIRATION_TIME_IN_SECS,
  "iat": $ISSUED_AT_TIME_IN_SECS,
  "jti": $RANDOMLY_GENERATED_UUID,
  "scope": "dpv:FraudPreventionAndDetection number-verification:device-phone-number:read"
}

FPNV 會使用自己的私密金鑰簽署 JWT,而電信業者可以使用對應的公開金鑰驗證 JWT。FPNV 會透過 JWKS 端點提供公開金鑰。由於 FPNV 會定期輪替公開金鑰 (例如每 30 天一次),因此電信業者應定期輪詢這個 JWKS 端點的公開金鑰 (例如每天一次)。

FPNV 的要求標頭

  • Content-Typeapplication/x-www-form-urlencoded
  • Acceptapplication/json

FPNV 的要求欄位

  • grant_typeurn:ietf:params:oauth:grant-type:jwt-bearer
  • assertion:上方建立的 JWT,並以 FPNV 的私密金鑰簽署
    • 請注意,這個 JWT 包含 TempToken
POST /token.oauth2 HTTP/1.1
Host: as.example.com
Content-Type: application/x-www-form-urlencoded
Accept: application/json

grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer
&assertion=$JWT
CAMARA 存取權杖 - 電信業者回應

電信業者的回應標頭

  • Content-Type:FPNV 預期回應類型會與要求中的 Accept 標頭相符
    • application/json

電信業者的回應欄位

  • access_token:CAMARA 存取權杖,之後可換取電話號碼
  • token_typebearer
  • expires_in:OAuth 存取權杖的到期時間 (以秒為單位)
    • Google 會驗證 OAuth 權杖的到期時間是否符合技術規定
  • scope:要求目的
    • dpv:FraudPreventionAndDetection number-verification:device-phone-number:read
200 OK
Content-Type: application/json

{
  "access_token": $CAMARA_ACCESS_TOKEN,
  "token_type": "bearer",
  "expires_in": $EXPIRATION_IN_SECS,
  "scope": "dpv:FraudPreventionAndDetection number-verification:device-phone-number:read"
}
CAMARA NumberVerification API v2

接著,Google 會向電信業者的 /device-phone-number 端點傳送 GET 要求,交換該 CAMARA 存取權杖。

CAMARA NumberVerification - GET Request to Carrier

FPNV 的要求標頭

  • AuthorizationBearer $CAMARA_ACCESS_TOKEN
  • Acceptapplication/json
GET /device-phone-number
Authorization: Bearer $CAMARA_ACCESS_TOKEN
Accept: application/json
Content-Type: application/json
CAMARA NumberVerification - Response from Carrier

電信業者的回應標頭

  • Content-Type:FPNV 預期回應類型會與要求中的 Accept 標頭相符
    • application/json

電信業者的回應欄位

  • devicePhoneNumber:傳回 E164 格式的電話號碼
200 OK
Content-Type: application/json

{
 "devicePhoneNumber": $PHONE_NUMBER
}