Auf der Seite Erste Schritte mit Firebase Phone Number Verification wird beschrieben, wie Sie Firebase PNV mithilfe der Methode getVerifiedPhoneNumber() einbinden. Diese Methode verarbeitet den gesamten Firebase PNV-Ablauf, von der Einholung der Nutzereinwilligung bis hin zu den erforderlichen Netzwerkaufrufen an das Firebase PNV-Backend.
Die API mit einer einzelnen Methode (getVerifiedPhoneNumber()) wird für die meisten Entwickler empfohlen. Wenn Sie jedoch eine genauere Kontrolle über die Interaktion mit dem Android Credential Manager benötigen, z. B. um andere Anmeldedaten zusammen mit der Telefonnummer anzufordern, bietet die Firebase PNV-Bibliothek auch die folgenden beiden Methoden, die jeweils eine andere Interaktion mit dem Firebase PNV-Backend verarbeiten:
getDigitalCredentialPayload()erhält eine vom Server signierte Anfrage, mit der Sie den Credential Manager aufrufen.exchangeCredentialResponseForPhoneNumber()tauscht die Antwort von Credential Manager gegen ein signiertes Token mit der bestätigten Telefonnummer aus. In diesem Schritt erfolgt die Abrechnung.
Zwischen dem Aufruf dieser Methoden sind Sie für die Interaktion mit den Credential Manager APIs von Android verantwortlich. Auf dieser Seite finden Sie eine Übersicht über die Implementierung dieses dreiteiligen Ablaufs.
Hinweis
Richten Sie Ihr Firebase-Projekt ein und importieren Sie die Firebase PNV-Abhängigkeiten, wie auf der Seite Erste Schritte beschrieben.
1. Nutzlast der Anfrage für digitale Anmeldedaten abrufen
Rufen Sie die Methode getDigitalCredentialPayload() auf, um eine Anfrage für die Telefonnummer des Geräts zu generieren. Im nächsten Schritt wird diese Anfrage zur Nutzlast Ihrer Interaktion mit der Credential Manager API.
Kotlin
// This instance does not require an Activity context.
val fpnv = FirebasePhoneNumberVerification.getInstance()
// Your request should include a nonce, which will propagate through the flow
// and be present in the final response from FPNV. See the section "Verifying
// the Firebase PNV token" for details on generating and verifying this.
val nonce = fetchNonceFromYourServer()
fpnv.getDigitalCredentialPayload(nonce, "https://example.com/privacy-policy")
.addOnSuccessListener { fpnvDigitalCredentialPayload ->
// Use the payload in the next step.
// ...
}
.addOnFailureListener { e -> /* Handle payload fetch failure */ }
2. Anfrage für einen digitalen Ausweis mit dem Credential Manager stellen
Leiten Sie die Anfrage dann an den Credential Manager weiter.
Dazu müssen Sie die Nutzlast der Anfrage in eine DigitalCredential API-Anfrage verpacken. Diese Anfrage muss dieselbe Nonce enthalten, die Sie an getDigitalCredentialPayload() übergeben haben.
Kotlin
// This example uses string interpolation for clarity, but you should use some kind of type-safe
// serialization method.
fun buildDigitalCredentialRequestJson(nonce: String, fpnvDigitalCredentialPayload: String) = """
{
"requests": [
{
"protocol": "openid4vp-v1-unsigned",
"data": {
"response_type": "vp_token",
"response_mode": "dc_api",
"nonce": "$nonce",
"dcql_query": { "credentials": [$fpnvDigitalCredentialPayload] }
}
}
]
}
""".trimIndent()
Anschließend können Sie die Anfrage mit der Credential Manager API stellen:
Kotlin
suspend fun makeFpnvRequest(
context: Activity, nonce: String, fpnvDigitalCredentialPayload: String): GetCredentialResponse {
// Helper function to build the digital credential request (defined above).
// Pass the same nonce you passed to getDigitalCredentialPayload().
val digitalCredentialRequestJson =
buildDigitalCredentialRequestJson(nonce, fpnvDigitalCredentialPayload)
// CredentialManager requires an Activity context.
val credentialManager = CredentialManager.create(context)
// Build a Credential Manager request that includes the Firebase PNV option. Note that
// you can't combine the digital credential option with other options.
val request = GetCredentialRequest.Builder()
.addCredentialOption(GetDigitalCredentialOption(digitalCredentialRequestJson))
.build()
// getCredential is a suspend function, so it must run in a coroutine scope,
val cmResponse: GetCredentialResponse = try {
credentialManager.getCredential(context, request)
} catch (e: GetCredentialException) {
// If the user cancels the operation, the feature isn't available, or the
// SIM doesn't support the feature, a GetCredentialCancellationException
// will be returned. Otherwise, a GetCredentialUnsupportedException will
// be returned with details in the exception message.
throw e
}
return cmResponse
}
Wenn der Aufruf des Credential Managers erfolgreich ist, enthält die Antwort einen digitalen Ausweis, den Sie mit Code wie im folgenden Beispiel extrahieren können:
Kotlin
val dcApiResponse = extractApiResponse(cmResponse)
fun extractApiResponse(response: GetCredentialResponse): String {
val credential = response.credential
when (credential) {
is DigitalCredential -> {
val json = JSONObject(credential.credentialJson)
val firebaseJwtArray =
json.getJSONObject("data").getJSONObject("vp_token").getJSONArray("firebase")
return firebaseJwtArray.getString(0)
}
else -> {
// Handle any unrecognized credential type here.
Log.e(TAG, "Unexpected type of credential ${credential.type}")
}
}
}
3. Antwort mit digitalen Anmeldedaten gegen ein Firebase PNV-Token austauschen
Rufen Sie schließlich die Methode exchangeCredentialResponseForPhoneNumber() auf, um die Antwort des digitalen Ausweises gegen die bestätigte Telefonnummer und ein Firebase PNV-Token einzutauschen:
Kotlin
fpnv.exchangeCredentialResponseForPhoneNumber(dcApiResponse)
.addOnSuccessListener { result ->
val phoneNumber = result.getPhoneNumber()
// Verification successful
}
.addOnFailureListener { e -> /* Handle exchange failure */ }
Dieser Schritt löst die Abrechnung aus, wenn er erfolgreich abgeschlossen wurde und die bestätigte Telefonnummer an Ihre App zurückgegeben wird.
4. Firebase PNV-Token verifizieren
Wenn der Ablauf erfolgreich ist, gibt die Methode getVerifiedPhoneNumber() die bestätigte Telefonnummer und ein signiertes Token zurück, das sie enthält. Sie können diese Daten in Ihrer App verwenden, wie in Ihrer Datenschutzerklärung dokumentiert.
Wenn du die bestätigte Telefonnummer außerhalb des App-Clients verwendest, solltest du das Token anstelle der Telefonnummer selbst weitergeben, damit du die Integrität der Nummer bei der Verwendung überprüfen kannst. Zum Überprüfen von Tokens müssen Sie zwei Endpunkte implementieren:
- Ein Endpunkt für die Nonce-Generierung
- Ein Endpunkt für die Tokenüberprüfung
Die Implementierung dieser Endpunkte liegt bei Ihnen. Die folgenden Beispiele zeigen, wie Sie sie mit Node.js und Express implementieren können.
Nonces generieren
Dieser Endpunkt ist für das Generieren und temporäre Speichern von Einmalwerten (Nonces) verantwortlich, die verwendet werden, um Replay-Angriffe auf Ihre Endpunkte zu verhindern. Beispiel für eine Express-Route:
Node.js
app.get('/fpnvNonce', async (req, res) => {
const nonce = crypto.randomUUID();
// TODO: Save the nonce to a database, key store, etc.
// You should also assign the nonce an expiration time and periodically
// clear expired nonces from your database.
await persistNonce({
nonce,
expiresAt: Date.now() + 180000, // Give it a short duration.
});
// Return the nonce to the caller.
res.send({ nonce });
});
Dies ist der Endpunkt, den die Platzhalterfunktion fetchNonceFromYourServer() in Schritt 1 aufrufen würde. Die Nonce wird über die verschiedenen Netzwerkaufrufe, die der Client ausführt, weitergegeben und schließlich im Firebase PNV-Token an Ihren Server zurückgegeben. Im nächsten Schritt prüfen Sie, ob das Token eine von Ihnen generierte Nonce enthält.
Tokens bestätigen
Dieser Endpunkt empfängt Firebase PNV-Tokens von Ihrem Client und prüft deren Authentizität. Zur Verifizierung eines Tokens müssen Sie Folgendes prüfen:
Der Header
typist aufJWTfestgelegt.Das Token wird mit einem der Schlüssel signiert, die am JWKS-Endpunkt Firebase PNV mit dem Algorithmus
ES256veröffentlicht wurden:https://fpnv.googleapis.com/v1beta/jwksDie Aussteller-Ansprüche enthalten Ihre Firebase-Projektnummer und haben das folgende Format:
https://fpnv.googleapis.com/projects/FIREBASE_PROJECT_NUMBERSie finden Ihre Firebase-Projektnummer in der Firebase Console auf dem Tab
Einstellungen > Allgemein.Der Zielgruppenanspruch ist eine Liste, die Ihre Firebase-Projektnummer und ‑Projekt-ID enthält und das folgende Format hat:
[ https://fpnv.googleapis.com/projects/FIREBASE_PROJECT_NUMBER, https://fpnv.googleapis.com/projects/FIREBASE_PROJECT_ID, ]Das Token ist nicht abgelaufen.
Das Token enthält eine gültige Nonce. Eine Nonce ist gültig, wenn:
- Sie haben es generiert (es ist also in dem von Ihnen verwendeten Persistenzmechanismus zu finden).
- Er wurde noch nicht verwendet.
- Es ist noch nicht abgelaufen.
Die Express-Implementierung könnte beispielsweise so aussehen:
Node.js
import { JwtVerifier } from "aws-jwt-verify";
// Find your Firebase project number in the Firebase console.
const FIREBASE_PROJECT_NUMBER = "123456789";
// The issuer and audience claims of the FPNV token are specific to your
// project.
const issuer = `https://fpnv.googleapis.com/projects/${FIREBASE_PROJECT_NUMBER}`;
const audience = `https://fpnv.googleapis.com/projects/${FIREBASE_PROJECT_NUMBER}`;
// The JWKS URL contains the current public signing keys for FPNV tokens.
const jwksUri = "https://fpnv.googleapis.com/v1beta/jwks";
// Configure a JWT verifier to check the following:
// - The token is signed by Google
// - The issuer and audience claims match your project
// - The token has not yet expired (default begavior)
const fpnvVerifier = JwtVerifier.create({ issuer, audience, jwksUri });
app.post('/verifiedPhoneNumber', async (req, res) => {
if (!req.body) return res.sendStatus(400);
// Get the token from the body of the request.
const fpnvToken = req.body;
try {
// Attempt to verify the token using the verifier configured above.
const verifiedPayload = await fpnvVerifier.verify(fpnvToken);
// Now that you've verified the signature and claims, verify the nonce.
// TODO: Try to look up the nonce in your database and remove it if it's
// found; if it's not found or it's expired, throw an error.
await testAndRemoveNonce(verifiedPayload.nonce);
// Only after verifying the JWT signature, claims, and nonce, get the
// verified phone number from the subject claim.
// You can use this value however it's needed by your app.
const verifiedPhoneNumber = verifiedPayload.sub;
// (Do something with it...)
return res.sendStatus(200);
} catch {
// If verification fails, reject the token.
return res.sendStatus(400);
}
});