Gérer les locataires Identity Platform par programmation
Ce document explique comment utiliser le SDK Admin Identity Platform pour gérer les locataires et leurs utilisateurs par programmation. Vous pouvez, par exemple, effectuer les actions suivantes en tant qu'administrateur :
Gestion des utilisateurs : créez, mettez à jour, supprimez et répertoriez les utilisateurs pour un locataire spécifique.
Validation de l'identité : identifiez les utilisateurs d'une application pour restreindre l'accès aux ressources de votre propre serveur.
Importation d'utilisateur : migrez des utilisateurs depuis un système d'authentification externe, ou un autre projet ou locataire Identity Platform.
Contrôle des accès avec revendications personnalisées : définissez des attributs personnalisés sur les comptes utilisateur pour un locataire spécifique et mettez en œuvre diverses stratégies de contrôle des accès, telles que le contrôle des accès basé sur les rôles.
Gestion des sessions utilisateur : révoquez les jetons d'actualisation d'un utilisateur pour un locataire spécifique.
Liens d'action par e-mail : générez des liens d'e-mail personnalisés pour la réinitialisation de mot de passe, la connexion par lien d'e-mail et la validation des e-mails pour les utilisateurs d'un locataire spécifique.
Gestion des locataires : créez, répertoriez, obtenez, mettez à jour et supprimez des locataires pour un projet Identity Platform spécifique.
Gestion des fournisseurs OIDC et SAML sur des locataires : gérez par programmation les configurations OIDC et SAML sur un locataire spécifié.
Avant de commencer
Installez le SDK Admin pour Node.js, Java, Python, Go ou C#.
Activez l'architecture mutualisée pour votre projet Google Cloud.
Fonctionnalités compatibles
Le tableau suivant répertorie les fonctionnalités compatibles avec chaque SDK dans un environnement mutualisé :
Fonctionnalité | Node.js | Java | Python | Go | C# |
---|---|---|---|---|---|
Émettre un jeton personnalisé | |||||
Valider des jetons d'ID | |||||
Gérer des comptes utilisateur | |||||
Contrôler les accès avec des revendications personnalisées | |||||
Révoquer des jetons d'actualisation | |||||
Importer des utilisateurs | |||||
Générer des liens d'action par e-mail | |||||
Authentification multifacteur | |||||
Gérer des configurations de fournisseurs SAML/OIDC | |||||
Gérer des cookies de session |
Le tableau suivant indique les méthodes de connexion que vous pouvez configurer à l'aide des SDK Admin et la console Google Cloud dans un contexte spécifique au locataire:
Caractéristique | console Google Cloud | SDK Admin |
---|---|---|
OIDC | ||
SAML | ||
Social | ||
Téléphone | ||
Authentification multifacteur | ||
Anonyme |
Gestion locative
Le SDK Admin vous permet de gérer les locataires par programmation à partir d'un de serveur sécurisé au lieu d'utiliser la console Google Cloud. Cela inclut la possibilité de créer, de répertorier, d'obtenir, de modifier ou de supprimer des locataires.
Chaque locataire contient des fournisseurs d'identité, des paramètres et des ensembles d'utilisateurs qui lui sont propres.
Les opérations de gestion de la configuration du locataire (CRUD) sont disponibles à partir de l'instance de projet parent à l'aide de admin.auth().tenantManager()
.
Une configuration de locataire fournit des informations sur un locataire, telles que son nom à afficher, son identifiant et sa configuration d'authentification d'e-mail.
Tous les autres paramètres (tels que les domaines en liste blanche et les URI de redirection authentifiés) d'un locataire sont hérités du projet parent. Ceux-ci doivent être gérés à l'aide de la console Google Cloud.
Pour les opérations telles que la gestion des utilisateurs spécifiques au locataire, la configuration de fournisseurs OIDC/SAML et la génération de liens par e-mail, vous avez besoin d'une instance TenantAwareAuth
pour le locataire cible (identifié par son tenantId
unique).
Node.js
const tenantManager = admin.auth().tenantManager();
const tenantAuth = tenantManager.authForTenant(tenantId);
Python
from firebase_admin import tenant_mgt tenant_client = tenant_mgt.auth_for_tenant(tenant_id)
Java
FirebaseAuth auth = FirebaseAuth.getInstance(); TenantManager tenantManager = auth.getTenantManager(); TenantAwareFirebaseAuth tenantAuth = tenantManager.getAuthForTenant(tenantId);
Tous les appels aux API de gestion des utilisateurs, aux API de gestion des fournisseurs OIDC/SAML et aux API de génération de liens d'e-mail font partie du champ d'application de ce locataire (en utilisant son instance TenantAwareAuth
).
Obtenir un locataire existant
Le SDK Admin fournit la méthode getTenant()
, qui récupère des informations sur un locataire en fonction de son tenantId
(identifiant unique du locataire).
Node.js
admin.auth().tenantManager().getTenant(tenantId)
.then((tenant) => {
console.log(tenant.toJSON());
})
.catch((error) => {
// Handle error.
});
Python
tenant = tenant_mgt.get_tenant(tenant_id) print('Retreieved tenant:', tenant.tenant_id)
Java
Tenant tenant = FirebaseAuth.getInstance().getTenantManager().getTenant(tenantId); System.out.println("Retrieved tenant: " + tenant.getTenantId());
Cette méthode renvoie un objet Tenant
correspondant au tenantId
.
Si le tenantId
fourni n'appartient pas à un locataire existant, la promesse renvoyée est rejetée avec l'erreur auth/tenant-not-found
.
Veillez à ne pas confondre une instance Tenant
avec un objet TenantAwareAuth
. authInstance.tenantManager().authForTenant()
renvoie une instance TenantAwareAuth
qui étend BaseAuth
.
La classe Auth
étend également BaseAuth
.
BaseAuth
fournit des API permettant de gérer les utilisateurs, et de configurer les fournisseurs OIDC/SAML dans différents contextes. Pour Auth
, le contexte est au niveau du projet parent.
Pour TenantAwareAuth
, le contexte est au niveau du locataire (le locataire est déterminé par l'ID du locataire). La méthode getTenant()
permet de résoudre les informations de base sur le locataire (telles que l'ID de locataire, le nom à afficher et les paramètres du fournisseur de messagerie), mais pour appeler les API sur ce locataire, vous devez utiliser authForTenant(tenantFromGetTenant.tenantId)
pour consulter nos règles en matière de publicité.
Créer un locataire
Utilisez la méthode createTenant()
pour créer une configuration de locataire :
Node.js
admin.auth().tenantManager().createTenant({
displayName: 'myTenant1',
emailSignInConfig: {
enabled: true,
passwordRequired: false, // Email link sign-in enabled.
},
// TODO: Remove if you don't want to enable multi-factor authentication.
multiFactorConfig: {
state: 'ENABLED',
factorIds: ['phone']
},
// TODO: Remove if you don't want to register test phone numbers for use
// with multi-factor authentication.
testPhoneNumbers: {
'+16505551234': '145678',
'+16505550000': '123456'
},
})
.then((createdTenant) => {
console.log(createdTenant.toJSON());
})
.catch((error) => {
// Handle error.
});
Python
tenant = tenant_mgt.create_tenant( display_name='myTenant1', enable_email_link_sign_in=True, allow_password_sign_up=True) print('Created tenant:', tenant.tenant_id)
Java
Tenant.CreateRequest request = new Tenant.CreateRequest() .setDisplayName("myTenant1") .setEmailLinkSignInEnabled(true) .setPasswordSignInAllowed(true); Tenant tenant = FirebaseAuth.getInstance().getTenantManager().createTenant(request); System.out.println("Created tenant: " + tenant.getTenantId());
Vous pouvez fournir n'importe quelle combinaison de ces propriétés :
Valeur | Type | Description |
---|---|---|
displayName |
string |
Nom à afficher du locataire. Il doit comporter entre 4 et 20 caractères, comprendre des lettres, des chiffres et des tirets, et doit commencer par une lettre. |
emailSignInConfig |
{ enable: boolean, passwordRequired: boolean } |
Configuration du fournisseur de connexion par e-mail. Ces informations indiquent si le fournisseur de messagerie est activé et si un mot de passe est requis pour la connexion par e-mail. Lorsque cet indicateur n'est pas obligatoire, la connexion par e-mail peut être effectuée à l'aide d'un mot de passe par connexion par lien d'e-mail. |
multiFactorConfig |
{ state: 'DISABLED' | 'ENABLED', factorIds: string[] } |
Indique si l'authentification multifacteur est activée pour le locataire et les types de facteurs autorisés. Actuellement, l'unique ID de facteur compatible est phone .
|
testPhoneNumbers |
{ string: string } |
Carte des numéros de téléphone et des codes d'authentification multifacteur associés à enregistrer à des fins de test.
Un maximum de 10 entrées est autorisé. Pour supprimer tous les numéros de téléphone de test, définissez ce champ sur null .
|
La méthode renvoie un objet Tenant
pour le locataire nouvellement créé.
Mettre à jour un locataire
Utilisez la méthode updateTenant()
pour modifier les données d'un locataire existant. Vous devez spécifier tenantId
, ainsi que les propriétés à mettre à jour pour ce locataire.
Node.js
admin.auth().tenantManager().updateTenant(tenantId, {
displayName: 'updatedName',
emailSignInConfig: {
enabled: false, // Disable email provider.
},
// Enable multi-factor authentication.
multiFactorConfig: {
state: 'ENABLED',
factorIds: ['phone']
},
// Register phone numbers for testing.
testPhoneNumbers: {
'+16505551234': '145678',
'+16505550000': '123456'
},
})
.then((updatedTenant) => {
console.log(updatedTenant.toJSON());
})
.catch((error) => {
// Handle error.
});
Python
tenant = tenant_mgt.update_tenant( tenant_id, display_name='updatedName', allow_password_sign_up=False) # Disable email provider print('Updated tenant:', tenant.tenant_id)
Java
Tenant.UpdateRequest request = new Tenant.UpdateRequest(tenantId) .setDisplayName("updatedName") .setPasswordSignInAllowed(false); Tenant tenant = FirebaseAuth.getInstance().getTenantManager().updateTenant(request); System.out.println("Updated tenant: " + tenant.getTenantId());
updateTenant()
accepte les mêmes propriétés que createTenant()
. Toutes les propriétés sont facultatives. Si une propriété n'est pas spécifiée, la valeur existante n'est pas modifiée.
La méthode renvoie un objet Tenant
mis à jour une fois l'opération terminée. Si le tenantId
fourni n'appartient pas à un locataire existant, la promesse renvoyée est rejetée avec l'erreur auth/tenant-not-found
.
Supprimer un locataire
Vous pouvez supprimer un locataire à l'aide de son tenantId
:
Node.js
admin.auth().tenantManager().deleteTenant(tenantId)
.then(() => {
// Tenant deleted.
})
.catch((error) => {
// Handle error.
});
Python
tenant_mgt.delete_tenant(tenant_id)
Java
FirebaseAuth.getInstance().getTenantManager().deleteTenant(tenantId);
La méthode renvoie un résultat vide une fois la suppression terminée.
Si le tenantId
fourni n'appartient pas à un locataire existant, la promesse renvoyée est rejetée avec l'erreur auth/tenant-not-found
.
Répertorier les locataires
Utilisez la méthode listTenants()
pour répertorier les locataires existants :
Node.js
function listAllTenants(nextPageToken) {
return admin.auth().tenantManager().listTenants(100, nextPageToken)
.then((result) => {
result.tenants.forEach((tenant) => {
console.log(tenant.toJSON());
});
if (result.pageToken) {
return listAllTenants(result.pageToken);
}
});
}
listAllTenants();
Python
for tenant in tenant_mgt.list_tenants().iterate_all(): print('Retrieved tenant:', tenant.tenant_id)
Java
ListTenantsPage page = FirebaseAuth.getInstance().getTenantManager().listTenants(null); for (Tenant tenant : page.iterateAll()) { System.out.println("Retrieved tenant: " + tenant.getTenantId()); }
Chaque lot de résultats contient une liste de locataires, ainsi qu'un jeton de page suivant pour répertorier le prochain lot de locataires. Lorsque tous les locataires ont déjà été répertoriés, aucun objet pageToken
n'est renvoyé.
Si aucun champ maxResults
n'est spécifié, la valeur par défaut est de 1 000 locataires par lot.
Il s'agit également du nombre maximal de locataires autorisés à la fois.
Toute valeur supérieure à la valeur maximale génère une erreur d'argument.
Si aucun élément pageToken
n'est spécifié, la méthode répertorie les locataires depuis le début.
Gérer les fournisseurs SAML et OIDC par programmation
Le SDK Admin fournit des API permettant de gérer les configurations de fournisseurs SAML (Security Assertion Markup Language) 2.0 et OIDC (OpenID Connect) par programmation à partir d'un environnement de serveur sécurisé.
Avec le SDK Admin, vous pouvez gérer ces fournisseurs pour un locataire spécifique. Cette opération est semblable à la gestion des fournisseurs OIDC et SAML au niveau du projet.
Pour gérer les fournisseurs d'un locataire, commencez par créer une instance TenantAwareAuth
:
Node.js
const tenantAuth = admin.auth().tenantManager().authForTenant('TENANT-ID');
Python
tenant_client = tenant_mgt.auth_for_tenant('TENANT-ID')
Java
TenantAwareFirebaseAuth tenantAuth = FirebaseAuth.getInstance().getTenantManager() .getAuthForTenant("TENANT-ID");
Vous pouvez ensuite effectuer des opérations courantes, telles que la création, la modification ou la suppression de fournisseurs pour un locataire.
Créer un fournisseur
Le code suivant montre comment créer un fournisseur SAML pour un locataire :
Node.js
const newConfig = {
displayName: 'SAML provider name',
enabled: true,
providerId: 'saml.myProvider',
idpEntityId: 'IDP_ENTITY_ID',
ssoURL: 'https://example.com/saml/sso/1234/',
x509Certificates: [
'-----BEGIN CERTIFICATE-----\nCERT1...\n-----END CERTIFICATE-----',
'-----BEGIN CERTIFICATE-----\nCERT2...\n-----END CERTIFICATE-----'
],
rpEntityId: 'RP_ENTITY_ID',
// Using the default callback URL.
callbackURL: 'https://project-id.firebaseapp.com/__/auth/handler'
};
tenantAuth.createProviderConfig(newConfig).then(() => {
// Successful creation.
}).catch((error) => {
// Handle error.
});
Python
saml = tenant_client.create_saml_provider_config( display_name='SAML provider name', enabled=True, provider_id='saml.myProvider', idp_entity_id='IDP_ENTITY_ID', sso_url='https://example.com/saml/sso/1234/', x509_certificates=[ '-----BEGIN CERTIFICATE-----\nCERT1...\n-----END CERTIFICATE-----', '-----BEGIN CERTIFICATE-----\nCERT2...\n-----END CERTIFICATE-----', ], rp_entity_id='P_ENTITY_ID', callback_url='https://project-id.firebaseapp.com/__/auth/handler') print('Created new SAML provider:', saml.provider_id)
Java
SamlProviderConfig.CreateRequest request = new SamlProviderConfig.CreateRequest() .setDisplayName("SAML provider name") .setEnabled(true) .setProviderId("saml.myProvider") .setIdpEntityId("IDP_ENTITY_ID") .setSsoUrl("https://example.com/saml/sso/1234/") .addX509Certificate("-----BEGIN CERTIFICATE-----\nCERT1...\n-----END CERTIFICATE-----") .addX509Certificate("-----BEGIN CERTIFICATE-----\nCERT2...\n-----END CERTIFICATE-----") .setRpEntityId("RP_ENTITY_ID") .setCallbackUrl("https://project-id.firebaseapp.com/__/auth/handler"); SamlProviderConfig saml = tenantAuth.createSamlProviderConfig(request); System.out.println("Created new SAML provider: " + saml.getProviderId());
Modifier un fournisseur
Le code suivant montre comment modifier un fournisseur :
Node.js
const updatedConfig = {
x509Certificates: [
'-----BEGIN CERTIFICATE-----\nCERT2...\n-----END CERTIFICATE-----',
'-----BEGIN CERTIFICATE-----\nCERT3...\n-----END CERTIFICATE-----',
],
};
tenantAuth.updateProviderConfig('saml.myProvider', updatedConfig).then(() => {
// Successful update.
}).catch((error) => {
// Handle error.
});
Python
saml = tenant_client.update_saml_provider_config( 'saml.myProvider', x509_certificates=[ '-----BEGIN CERTIFICATE-----\nCERT2...\n-----END CERTIFICATE-----', '-----BEGIN CERTIFICATE-----\nCERT3...\n-----END CERTIFICATE-----', ]) print('Updated SAML provider:', saml.provider_id)
Java
SamlProviderConfig.UpdateRequest request = new SamlProviderConfig.UpdateRequest("saml.myProvider") .addX509Certificate("-----BEGIN CERTIFICATE-----\nCERT2...\n-----END CERTIFICATE-----") .addX509Certificate("-----BEGIN CERTIFICATE-----\nCERT3...\n-----END CERTIFICATE-----"); SamlProviderConfig saml = tenantAuth.updateSamlProviderConfig(request); System.out.println("Updated SAML provider: " + saml.getProviderId());
Obtenir un fournisseur
Le code suivant montre comment récupérer la configuration de fournisseur pour un locataire spécifique à l'aide de son ID de fournisseur :
Node.js
tenantAuth.getProviderConfig('saml.myProvider').then((config) => {
// Get display name and whether it is enabled.
console.log(config.displayName, config.enabled);
}).catch((error) => {
// Handle error. Common error is that config is not found.
});
Python
saml = tennat_client.get_saml_provider_config('saml.myProvider') print(saml.display_name, saml.enabled)
Java
SamlProviderConfig saml = tenantAuth.getSamlProviderConfig("saml.myProvider"); // Get display name and whether it is enabled. System.out.println(saml.getDisplayName() + " " + saml.isEnabled());
Répertorier les fournisseurs
Le code suivant montre comment répertorier les configurations de fournisseur pour un locataire donné :
Node.js
// Returns 10 SAML provider configs starting from the specified nextPageToken offset.
tenantAuth.listProviderConfigs({type: 'saml', maxResults: 10, pageToken: 'nextPageToken'}).then((results) => {
results.providerConfigs.forEach((config) => {
console.log(config.providerId);
});
// To list the next 10:
// return tenantAuth.listProviderConfigs(
// {type: 'saml', maxResults: 10, pageToken: results.pageToken});
}).catch((error) => {
// Handle error.
});
Python
for saml in tenant_client.list_saml_provider_configs('nextPageToken').iterate_all(): print(saml.provider_id)
Java
ListProviderConfigsPage<SamlProviderConfig> page = tenantAuth.listSamlProviderConfigs( "nextPageToken"); for (SamlProviderConfig saml : page.iterateAll()) { System.out.println(saml.getProviderId()); }
Supprimer un fournisseur
Le code suivant montre comment supprimer un fournisseur :
Node.js
tenantAuth.deleteProviderConfig('saml.myProvider').then(() => {
// Successful deletion.
}).catch((error) => {
// Handle error.
});
Python
tenant_client.delete_saml_provider_config('saml.myProvider')
Java
tenantAuth.deleteSamlProviderConfig("saml.myProvider");
Les fournisseurs OIDC sont gérés de la même manière que les fournisseurs OIDC au niveau du projet, à ceci près qu'ils peuvent être gérés à partir de l'instance TenantAwareAuth
correspondante, plutôt que d'une instance de niveau projet Auth
.
Pour en savoir plus, consultez la page Gérer les fournisseurs SAML et OIDC par programmation.
Gérer des utilisateurs spécifiques au locataire
Vous pouvez utiliser le SDK Admin pour créer, récupérer, mettre à jour, supprimer et répertorier tous les utilisateurs d'un locataire spécifique.
Pour commencer, vous avez besoin d'une instance TenantAwareAuth
pour le locataire correspondant :
Node.js
const tenantAuth = admin.auth().tenantManager().authForTenant('TENANT-ID');
Python
tenant_client = tenant_mgt.auth_for_tenant('TENANT-ID')
Java
TenantAwareFirebaseAuth tenantAuth = FirebaseAuth.getInstance().getTenantManager() .getAuthForTenant("TENANT-ID");
Obtenir un compte utilisateur
Vous pouvez récupérer un utilisateur spécifique au locataire à l'aide d'un identifiant uid
:
Node.js
tenantAuth.getUser(uid)
.then((userRecord) => {
// See the UserRecord reference documentation to learn more.
console.log('Successfully fetched user data:', userRecord.toJSON());
// Tenant ID will be reflected in userRecord.tenantId.
})
.catch((error) => {
console.log('Error fetching user data:', error);
});
Python
# Get an auth.Client from tenant_mgt.auth_for_tenant() user = tenant_client.get_user(uid) print('Successfully fetched user data:', user.uid)
Java
// Get an auth client from the firebase.App UserRecord user = tenantAuth.getUser(uid); System.out.println("Successfully fetched user data: " + user.getDisplayName());
Vous pouvez également identifier un utilisateur par son adresse e-mail :
Node.js
tenantAuth.getUserByEmail(email)
.then((userRecord) => {
// See the UserRecord reference documentation to learn more.
console.log('Successfully fetched user data:', userRecord.toJSON());
// Tenant ID will be reflected in userRecord.tenantId.
})
.catch((error) => {
console.log('Error fetching user data:', error);
});
Python
user = tenant_client.get_user_by_email(email) print('Successfully fetched user data:', user.uid)
Java
// Get an auth client from the firebase.App UserRecord user = tenantAuth.getUserByEmail(email); System.out.println("Successfully fetched user data: " + user.getDisplayName());
Créer un utilisateur
Utilisez la méthode createUser()
afin de créer des utilisateurs pour un locataire spécifique.
Lorsque vous créez un utilisateur, fournir un uid
est facultatif. Si aucun n'est spécifié, Identity Platform en fournit un unique.
Node.js
tenantAuth.createUser({
email: 'user@example.com',
emailVerified: false,
phoneNumber: '+11234567890',
password: 'secretPassword',
displayName: 'John Doe',
photoURL: 'http://www.example.com/12345678/photo.png',
disabled: false
})
.then((userRecord) => {
// See the UserRecord reference documentation to learn more.
console.log('Successfully created new user:', userRecord.uid);
// Tenant ID will be reflected in userRecord.tenantId.
})
.catch((error) => {
console.log('Error creating new user:', error);
});
Python
user = tenant_client.create_user( email='user@example.com', email_verified=False, phone_number='+15555550100', password='secretPassword', display_name='John Doe', photo_url='http://www.example.com/12345678/photo.png', disabled=False) print('Sucessfully created new user:', user.uid)
Java
UserRecord.CreateRequest request = new UserRecord.CreateRequest() .setEmail("user@example.com") .setEmailVerified(false) .setPhoneNumber("+15555550100") .setPassword("secretPassword") .setDisplayName("John Doe") .setPhotoUrl("http://www.example.com/12345678/photo.png") .setDisabled(false); UserRecord user = tenantAuth.createUser(request); System.out.println("Successfully created user: " + user.getDisplayName());
Modifier un compte utilisateur
Vous pouvez modifier des utilisateurs existants en spécifiant leur uid
dans la méthode updateUser()
:
Node.js
tenantAuth.updateUser(uid, {
email: 'modifiedUser@example.com',
phoneNumber: '+11234567890',
emailVerified: true,
password: 'newPassword',
displayName: 'Jane Doe',
photoURL: 'http://www.example.com/12345678/photo.png',
disabled: true
})
.then((userRecord) => {
// See the UserRecord reference documentation to learn more.
console.log('Successfully updated user', userRecord.toJSON());
})
.catch((error) => {
console.log('Error updating user:', error);
});
Python
user = tenant_client.update_user( uid, email='user@example.com', phone_number='+15555550100', email_verified=True, password='newPassword', display_name='John Doe', photo_url='http://www.example.com/12345678/photo.png', disabled=True) print('Sucessfully updated user:', user.uid)
Java
UserRecord.UpdateRequest request = new UserRecord.UpdateRequest(uid) .setEmail("user@example.com") .setEmailVerified(true) .setPhoneNumber("+15555550100") .setPassword("newPassword") .setDisplayName("John Doe") .setPhotoUrl("http://www.example.com/12345678/photo.png") .setDisabled(true); UserRecord user = tenantAuth.updateUser(request); System.out.println("Successfully updated user: " + user.getDisplayName());
Supprimer un compte utilisateur
L'exemple suivant montre comment supprimer un utilisateur en fonction de son uid
:
Node.js
tenantAuth.deleteUser(uid)
.then(() => {
console.log('Successfully deleted user');
})
.catch((error) => {
console.log('Error deleting user:', error);
});
Python
tenant_client.delete_user(uid) print('Successfully deleted user')
Java
tenantAuth.deleteUser(uid); System.out.println("Successfully deleted user: " + uid);
Répertorier les utilisateurs
Pour récupérer la liste complète des utilisateurs pour un locataire spécifique par lot, utilisez la méthode listUsers()
. Chaque lot contient une liste de fiches utilisateur, ainsi qu'un jeton de page suivant si d'autres utilisateurs restent.
Node.js
function listAllUsers(nextPageToken) {
// List batch of users, 1000 at a time.
tenantAuth.listUsers(1000, nextPageToken)
.then((listUsersResult) => {
listUsersResult.users.forEach((userRecord) => {
console.log('user', userRecord.toJSON());
// Tenant ID will be reflected in userRecord.tenantId.
});
if (listUsersResult.pageToken) {
// List next batch of users.
listAllUsers(listUsersResult.pageToken);
}
})
.catch((error) => {
console.log('Error listing users:', error);
});
}
// Start listing users from the beginning, 1000 at a time.
listAllUsers();
Python
# Note, behind the scenes, the iterator will retrive 1000 users at a time through the API for user in tenant_client.list_users().iterate_all(): print('User: ' + user.uid) # Iterating by pages of 1000 users at a time. page = tenant_client.list_users() while page: for user in page.users: print('User: ' + user.uid) # Get next batch of users. page = page.get_next_page()
Java
// Note, behind the scenes, the ListUsersPage retrieves 1000 Users at a time // through the API ListUsersPage page = tenantAuth.listUsers(null); for (ExportedUserRecord user : page.iterateAll()) { System.out.println("User: " + user.getUid()); } // Iterating by pages 100 users at a time. page = tenantAuth.listUsers(null, 100); while (page != null) { for (ExportedUserRecord user : page.getValues()) { System.out.println("User: " + user.getUid()); } page = page.getNextPage(); }
Consultez la documentation de SDK Admin portant sur la gestion des utilisateurs pour en savoir plus.
Importer des utilisateurs
Vous pouvez utiliser le SDK Admin pour importer des utilisateurs de manière groupée dans un locataire spécifique doté de privilèges élevés. Cela offre de nombreux avantages, comme la possibilité de migrer des utilisateurs depuis un autre produit Identity Platform, d'un autre locataire ou d'un système d'authentification externe à l'aide d'un différents algorithmes de hachage. Vous pouvez également importer directement des utilisateurs de fournisseurs fédérés (tels que SAML et OIDC) et bénéficier de revendications personnalisées directement.
Pour commencer, procurez-vous une instance TenantAwareAuth
pour le locataire correspondant :
Node.js
const tenantAuth = admin.auth().tenantManager().authForTenant('TENANT-ID');
Python
tenant_client = tenant_mgt.auth_for_tenant('TENANT-ID')
Java
TenantAwareFirebaseAuth tenantAuth = FirebaseAuth.getInstance().getTenantManager() .getAuthForTenant("TENANT-ID");
Vous pouvez importer jusqu'à 1 000 utilisateurs simultanément à l'aide d'un algorithme de hachage spécifique.
Node.js
tenantAuth.importUsers([{
uid: 'uid1',
email: 'user1@example.com',
// Must be provided in a byte buffer.
passwordHash: Buffer.from('password-hash-1'),
// Must be provided in a byte buffer.
passwordSalt: Buffer.from('salt1')
},
{
uid: 'uid2',
email: 'user2@example.com',
// Must be provided in a byte buffer.
passwordHash: Buffer.from('password-hash-2'),
// Must be provided in a byte buffer.
passwordSalt: Buffer.from('salt2')
}], {
hash: {
algorithm: 'HMAC_SHA256',
// Must be provided in a byte buffer.
key: Buffer.from('secret')
}
})
.then((results) => {
results.errors.forEach(function(indexedError) {
console.log('Error importing user ' + indexedError.index);
});
})
.catch((error) => {
console.log('Error importing users:', error);
});
Python
users = [ auth.ImportUserRecord( uid='uid1', email='user1@example.com', password_hash=b'password_hash_1', password_salt=b'salt1' ), auth.ImportUserRecord( uid='uid2', email='user2@example.com', password_hash=b'password_hash_2', password_salt=b'salt2' ), ] hash_alg = auth.UserImportHash.hmac_sha256(key=b'secret') try: result = tenant_client.import_users(users, hash_alg=hash_alg) for err in result.errors: print('Failed to import user:', err.reason) except exceptions.FirebaseError as error: print('Error importing users:', error)
Java
List<ImportUserRecord> users = new ArrayList<>(); users.add(ImportUserRecord.builder() .setUid("uid1") .setEmail("user1@example.com") .setPasswordHash("password-hash-1".getBytes()) .setPasswordSalt("salt1".getBytes()) .build()); users.add(ImportUserRecord.builder() .setUid("uid2") .setEmail("user2@example.com") .setPasswordHash("password-hash-2".getBytes()) .setPasswordSalt("salt2".getBytes()) .build()); UserImportHash hmacSha256 = HmacSha256.builder() .setKey("secret".getBytes()) .build(); UserImportResult result = tenantAuth.importUsers(users, UserImportOptions.withHash(hmacSha256)); for (ErrorInfo error : result.getErrors()) { System.out.println("Failed to import user: " + error.getReason()); }
Le paramètre tenantId
de tous les utilisateurs importés est défini sur tenantAuth.tenantId
.
Les utilisateurs sans mot de passe peuvent également être importés vers un locataire spécifique. Ces utilisateurs peuvent être importés avec des fournisseurs fédérés et des revendications personnalisées.
Node.js
tenantAuth.importUsers([{
uid: 'some-uid',
displayName: 'John Doe',
email: 'johndoe@acme.com',
photoURL: 'http://www.example.com/12345678/photo.png',
emailVerified: true,
phoneNumber: '+11234567890',
// Set this user as admin.
customClaims: {admin: true},
// User with SAML provider.
providerData: [{
uid: 'saml-uid',
email: 'johndoe@acme.com',
displayName: 'John Doe',
photoURL: 'http://www.example.com/12345678/photo.png',
providerId: 'saml.acme'
}]
}])
.then(function(results) {
results.errors.forEach(function(indexedError) {
console.log('Error importing user ' + indexedError.index);
});
})
.catch(function(error) {
console.log('Error importing users:', error);
});
Python
users = [ auth.ImportUserRecord( uid='some-uid', display_name='John Doe', email='johndoe@gmail.com', photo_url='http://www.example.com/12345678/photo.png', email_verified=True, phone_number='+11234567890', custom_claims={'admin': True}, # set this user as admin provider_data=[ # user with SAML provider auth.UserProvider( uid='saml-uid', email='johndoe@gmail.com', display_name='John Doe', photo_url='http://www.example.com/12345678/photo.png', provider_id='saml.acme' ) ], ), ] try: result = tenant_client.import_users(users) for err in result.errors: print('Failed to import user:', err.reason) except exceptions.FirebaseError as error: print('Error importing users:', error)
Java
List<ImportUserRecord> users = new ArrayList<>(); users.add(ImportUserRecord.builder() .setUid("some-uid") .setDisplayName("John Doe") .setEmail("johndoe@acme.com") .setPhotoUrl("https://www.example.com/12345678/photo.png") .setEmailVerified(true) .setPhoneNumber("+11234567890") // Set this user as admin. .putCustomClaim("admin", true) // User with SAML provider. .addUserProvider(UserProvider.builder() .setUid("saml-uid") .setEmail("johndoe@acme.com") .setDisplayName("John Doe") .setPhotoUrl("https://www.example.com/12345678/photo.png") .setProviderId("saml.acme") .build()) .build()); UserImportResult result = tenantAuth.importUsers(users); for (ErrorInfo error : result.getErrors()) { System.out.println("Failed to import user: " + error.getReason()); }
Consultez la section Importer des utilisateurs de la documentation de SDK Admin pour en savoir plus.
Validation de l'identité
Lorsqu'une application cliente Identity Platform communique avec un serveur backend personnalisé, l'utilisateur actuellement connecté doit être identifié sur ce serveur. Pour ce faire, vous pouvez envoyer le jeton d'ID de l'utilisateur une fois la connexion établie avec votre serveur. Le serveur peut ensuite vérifier l'intégrité et l'authenticité du jeton d'ID.
Le SDK Admin dispose d'une méthode intégrée de vérification et de décodage de jetons d'ID pour un locataire spécifique.
Après avoir connecté un utilisateur à un locataire spécifique du client, récupérez le jeton d'ID de l'utilisateur à l'aide du SDK client :
auth.tenantId = 'TENANT-ID';
auth.signInWithEmailAndPassword('user@example.com', 'password')
.then((userCredential) => {
return userCredential.user.getIdToken();
})
.then((idToken) => {
// Send the ID token to server for verification. ID token should be scoped to TENANT-ID.
});
Créez une instance TenantAwareAuth
sur le serveur :
Node.js
const tenantAuth = admin.auth().tenantManager().authForTenant('TENANT-ID');
Python
tenant_client = tenant_mgt.auth_for_tenant('TENANT-ID')
Java
TenantAwareFirebaseAuth tenantAuth = FirebaseAuth.getInstance().getTenantManager() .getAuthForTenant("TENANT-ID");
Vous pouvez ensuite valider le jeton d'ID de ce locataire spécifique :
Node.js
// idToken comes from the client app
tenantAuth.verifyIdToken(idToken)
.then((decodedToken) => {
let uid = decodedToken.uid;
// This should be set to TENANT-ID. Otherwise auth/mismatching-tenant-id error thrown.
console.log(decodedToken.firebase.tenant);
// ...
}).catch((error) => {
// Handle error
});
Une ressource côté serveur peut être accessible par plusieurs locataires avec différentes différents niveaux d'accès. Il est possible que l'ID du locataire ne soit pas connu à l'avance dans ce le jeton d'ID peut d'abord être vérifié au niveau du projet.
admin.auth().verifyIdToken(idToken)
.then((decodedToken) => {
if (decodedToken.firebase.tenant === 'TENANT-ID1') {
// Allow appropriate level of access for TENANT-ID1.
} else if (decodedToken.firebase.tenant === 'TENANT-ID2') {
// Allow appropriate level of access for TENANT-ID2.
} else {
// Block access for all other tenants.
throw new Error('Access not allowed.');
}
}).catch((error) => {
// Handle error
});
Python
# id_token comes from the client app try: decoded_token = tenant_client.verify_id_token(id_token) # This should be set to TENANT-ID. Otherwise TenantIdMismatchError error raised. print('Verified ID token from tenant:', decoded_token['firebase']['tenant']) except tenant_mgt.TenantIdMismatchError: # Token revoked, inform the user to reauthenticate or signOut(). pass
Java
try { // idToken comes from the client app FirebaseToken token = tenantAuth.verifyIdToken(idToken); // TenantId on the FirebaseToken should be set to TENANT-ID. // Otherwise "tenant-id-mismatch" error thrown. System.out.println("Verified ID token from tenant: " + token.getTenantId()); } catch (FirebaseAuthException e) { System.out.println("error verifying ID token: " + e.getMessage()); }
Consultez la section Valider les jetons d'ID dans la documentation du SDK Admin pour en savoir plus.
Gérer les sessions utilisateur
Les sessions Identity Platform sont de longue durée. Chaque fois qu'un utilisateur se connecte, les identifiants de l'utilisateur sont validés sur le serveur Identity Platform, puis échangés contre un jeton d'ID court et un jeton d'actualisation permanent. Les jetons d'ID durent une heure. Les jetons d'actualisation n'expirent jamais, sauf lorsqu'un utilisateur est désactivé, supprimé ou concerné par une modification importante du compte (par exemple, mise à jour de l'e-mail ou du mot de passe).
Dans certains cas, le jeton d'actualisation d'un utilisateur peut nécessiter d'être révoqué pour des raisons de sécurité (par exemple, le signalement par l'utilisateur de la perte ou du vol d'un appareil, la découverte d'une faille générale dans une application ou une fuite à grande échelle de jetons actifs). Le SDK Admin fournit une API permettant de révoquer tous les jetons d'actualisation émis pour un utilisateur spécifié d'un locataire spécifique.
Pour commencer, vous avez besoin d'une instance TenantAwareAuth
:
Node.js
const tenantAuth = admin.auth().tenantManager().authForTenant('TENANT-ID');
Python
tenant_client = tenant_mgt.auth_for_tenant('TENANT-ID')
Java
TenantAwareFirebaseAuth tenantAuth = FirebaseAuth.getInstance().getTenantManager() .getAuthForTenant("TENANT-ID");
Vous pouvez ensuite révoquer les jetons d'actualisation en spécifiant le paramètre uid
de cet utilisateur :
Node.js
// Revoke all refresh tokens for a specified user in a specified tenant for whatever reason.
// Retrieve the timestamp of the revocation, in seconds since the epoch.
tenantAuth.revokeRefreshTokens(uid)
.then(() => {
return tenantAuth.getUser(uid);
})
.then((userRecord) => {
return new Date(userRecord.tokensValidAfterTime).getTime() / 1000;
})
.then((timestamp) => {
console.log('Tokens revoked at: ', timestamp);
});
Python
# Revoke all refresh tokens for a specified user in a specified tenant for whatever reason. # Retrieve the timestamp of the revocation, in seconds since the epoch. tenant_client.revoke_refresh_tokens(uid) user = tenant_client.get_user(uid) # Convert to seconds as the auth_time in the token claims is in seconds. revocation_second = user.tokens_valid_after_timestamp / 1000 print('Tokens revoked at: {0}'.format(revocation_second))
Java
// Revoke all refresh tokens for a specified user in a specified tenant for whatever reason. // Retrieve the timestamp of the revocation, in seconds since the epoch. tenantAuth.revokeRefreshTokens(uid); // accessing the user's TokenValidAfter UserRecord user = tenantAuth.getUser(uid); long timestamp = user.getTokensValidAfterTimestamp() / 1000; System.out.println("the refresh tokens were revoked at: " + timestamp + " (UTC seconds)");
Une fois les jetons d'actualisation révoqués, aucun nouveau jeton d'ID ne peut être émis pour cet utilisateur tant que ce dernier ne s'authentifie pas de nouveau. Toutefois, les jetons d'ID existants demeurent actifs jusqu'à leur heure d'expiration naturelle (une heure).
Vous pouvez vérifier qu'un jeton d'ID valide non expiré n'est pas révoqué en spécifiant le paramètre checkRevoked
facultatif. Cela permet de vérifier qu'un jeton est révoqué une fois son intégrité et son authenticité validées.
Node.js
// Verify the ID token for a specific tenant while checking if the token is revoked by passing
// checkRevoked true.
let checkRevoked = true;
tenantAuth.verifyIdToken(idToken, checkRevoked)
.then(payload => {
// Token is valid.
})
.catch(error => {
if (error.code == 'auth/id-token-revoked') {
// Token has been revoked. Inform the user to re-authenticate or
// signOut() the user.
} else {
// Token is invalid.
}
});
Python
# Verify the ID token for a specific tenant while checking if the token is revoked. try: # Verify the ID token while checking if the token is revoked by # passing check_revoked=True. decoded_token = tenant_client.verify_id_token(id_token, check_revoked=True) # Token is valid and not revoked. uid = decoded_token['uid'] except tenant_mgt.TenantIdMismatchError: # Token belongs to a different tenant. pass except auth.RevokedIdTokenError: # Token revoked, inform the user to reauthenticate or signOut(). pass except auth.UserDisabledError: # Token belongs to a disabled user record. pass except auth.InvalidIdTokenError: # Token is invalid pass
Java
// Verify the ID token for a specific tenant while checking if the token is revoked. boolean checkRevoked = true; try { FirebaseToken token = tenantAuth.verifyIdToken(idToken, checkRevoked); System.out.println("Verified ID token for: " + token.getUid()); } catch (FirebaseAuthException e) { if ("id-token-revoked".equals(e.getErrorCode())) { // Token is revoked. Inform the user to re-authenticate or signOut() the user. } else { // Token is invalid } }
Consultez la documentation du SDK Admin sur la gestion des sessions pour en savoir plus.
Contrôler les accès avec des revendications personnalisées
Le SDK Admin permet de définir des attributs personnalisés sur les comptes utilisateur d'un locataire spécifique. Ces attributs vous permettent de mettre en œuvre différentes stratégies de contrôle d'accès, telles que le contrôle des accès basé sur les rôles. Les attributs peuvent être utilisés pour accorder aux utilisateurs différents niveaux d'accès appliqués par les règles de sécurité de l'application.
Pour commencer, procurez-vous une instance TenantAwareAuth
pour le locataire correspondant :
Node.js
const tenantAuth = admin.auth().tenantManager().authForTenant('TENANT-ID');
Python
tenant_client = tenant_mgt.auth_for_tenant('TENANT-ID')
Java
TenantAwareFirebaseAuth tenantAuth = FirebaseAuth.getInstance().getTenantManager() .getAuthForTenant("TENANT-ID");
Les revendications personnalisées peuvent contenir des données sensibles. Elles ne doivent donc être définies qu'à partir d'un environnement de serveur privilégié à l'aide du SDK Admin.
Node.js
// Set admin privilege on the user corresponding to uid for a specific tenant.
tenantAuth.setCustomUserClaims(uid, {admin: true}).then(() => {
// The new custom claims will propagate to the user's ID token the
// next time a new one is issued.
});
Python
# Set admin privilege on the user corresponding to uid. tenant_client.set_custom_user_claims(uid, {'admin': True}) # The new custom claims will propagate to the user's ID token the # next time a new one is issued.
Java
// Set admin privilege on the user corresponding to uid in a specific tenant. Map<String, Object> claims = new HashMap<>(); claims.put("admin", true); tenantAuth.setCustomUserClaims(uid, claims); // The new custom claims will propagate to the user's ID token the // next time a new one is issued.
Les attributs personnalisés nouvellement définis apparaîtront sur les attributs de premier niveau de la charge utile du jeton la prochaine fois que l'utilisateur se connecte ou actualise ses jetons d'ID sur une session existante. Dans l'exemple précédent, le jeton d'ID contient une revendication supplémentaire : {admin: true}
.
Après la validation du jeton d'ID et le décodage de sa charge utile, les revendications personnalisées supplémentaires peuvent être vérifiées pour appliquer le contrôle des accès.
Node.js
// Verify the ID token first.
tenantAuth.verifyIdToken(idToken).then((claims) => {
if (claims.admin === true) {
// Allow access to requested admin resource.
}
});
Python
# Verify the ID token first. claims = tenant_client.verify_id_token(id_token) if claims['admin'] is True: # Allow access to requested admin resource. pass
Java
// Verify the ID token first. FirebaseToken token = tenantAuth.verifyIdToken(idToken); if (Boolean.TRUE.equals(token.getClaims().get("admin"))) { //Allow access to requested admin resource. } // Verify the ID token first. FirebaseToken decoded = tenantAuth.verifyIdToken(idToken); if (Boolean.TRUE.equals(decoded.getClaims().get("admin"))) { // Allow access to requested admin resource. }
Les revendications personnalisées pour un utilisateur existant pour un locataire spécifique sont également disponibles en tant que propriété dans la fiche de l'utilisateur.
Node.js
// Lookup the user associated with the specified uid.
tenantAuth.getUser(uid).then((userRecord) => {
// The claims can be accessed on the user record.
console.log(userRecord.customClaims.admin);
});
Python
# Lookup the user associated with the specified uid. user = tenant_client.get_user(uid) # The claims can be accessed on the user record. print(user.custom_claims.get('admin'))
Java
// Lookup the user associated with the specified uid in a specific tenant. UserRecord user = tenantAuth.getUser(uid); System.out.println(user.getCustomClaims().get("admin"));
Pour en savoir plus, consultez la documentation du SDK Admin sur les revendications personnalisées.
Générer des liens d'action par e-mail
À l'aide des SDK Identity Platform clients, vous pouvez envoyer aux utilisateurs des adresses e-mail de locataires spécifiques contenant des liens qu'ils peuvent utiliser pour réinitialiser les mots de passe, valider l'adresse e-mail et se connecter par e-mail. Ces e-mails sont envoyés par Google et offrent une personnalisation limitée.
Avec le SDK Admin, vous pouvez générer ces liens par programmation dans le champ d'application d'un locataire spécifique.
Pour commencer, procurez-vous une instance TenantAwareAuth
pour le locataire correspondant :
Node.js
const tenantAuth = admin.auth().tenantManager().authForTenant('TENANT-ID');
Python
tenant_client = tenant_mgt.auth_for_tenant('TENANT-ID')
Java
TenantAwareFirebaseAuth tenantAuth = FirebaseAuth.getInstance().getTenantManager() .getAuthForTenant("TENANT-ID");
L'exemple suivant montre comment générer un lien afin de valider l'adresse e-mail d'un utilisateur pour un locataire spécifié :
Node.js
const actionCodeSettings = {
// URL you want to redirect back to. The domain (www.example.com) for
// this URL must be whitelisted in the Cloud console.
url: 'https://www.example.com/checkout?cartId=1234',
// This must be true for email link sign-in.
handleCodeInApp: true,
iOS: {
bundleId: 'com.example.ios'
},
android: {
packageName: 'com.example.android',
installApp: true,
minimumVersion: '12'
},
// FDL custom domain.
dynamicLinkDomain: 'coolapp.page.link'
};
// Admin SDK API to generate the email verification link.
const userEmail = 'user@example.com';
tenantAuth.generateEmailVerificationLink(userEmail, actionCodeSettings)
.then((link) => {
// Construct email verification template, embed the link and send
// using custom SMTP server.
return sendCustomVerificationEmail(userEmail, displayName, link);
})
.catch((error) => {
// Some error occurred.
});
Python
action_code_settings = auth.ActionCodeSettings( url='https://www.example.com/checkout?cartId=1234', handle_code_in_app=True, ios_bundle_id='com.example.ios', android_package_name='com.example.android', android_install_app=True, android_minimum_version='12', # FDL custom domain. dynamic_link_domain='coolapp.page.link', ) email = 'user@example.com' link = tenant_client.generate_email_verification_link(email, action_code_settings) # Construct email from a template embedding the link, and send # using a custom SMTP server. send_custom_email(email, link)
Java
ActionCodeSettings actionCodeSettings = ActionCodeSettings.builder() // URL you want to redirect back to. The domain (www.example.com) for // this URL must be whitelisted in the GCP Console. .setUrl("https://www.example.com/checkout?cartId=1234") // This must be true for email link sign-in. .setHandleCodeInApp(true) .setIosBundleId("com.example.ios") .setAndroidPackageName("com.example.android") .setAndroidInstallApp(true) .setAndroidMinimumVersion("12") // FDL custom domain. .setDynamicLinkDomain("coolapp.page.link") .build(); String link = tenantAuth.generateEmailVerificationLink(email, actionCodeSettings); // Construct email verification template, embed the link and send // using custom SMTP server. sendCustomEmail(email, displayName, link);
Des mécanismes similaires sont disponibles pour générer des liens de réinitialisation du mot de passe et de connexion via e-mail. Notez que lorsque vous générez un lien d'action par e-mail dans un contexte de locataire, l'ID de locataire doit être analysé à partir du lien et défini sur l'instance Auth
cliente pour que le code puisse être appliqué.
const actionCodeUrl = firebase.auth.ActionCodeURL.parseLink(window.location.href);
// A one-time code, used to identify and verify a request.
const code = actionCodeUrl.code;
// The tenant ID being used to trigger the email action.
const tenantId = actionCodeUrl.tenantId;
auth.tenantId = tenantId;
// Apply the action code.
auth.applyActionCode(actionCode)
.then(() => {
// User's email is now verified.
})
.catch((error) => {
// Handle error.
});
Pour en savoir plus, consultez la section Liens d'action par e-mail dans la documentation du SDK Admin.
Messages d'erreur
Le tableau suivant répertorie les messages d'erreur courants que vous pouvez rencontrer.
Code d'erreur | Description et étapes de résolution |
---|---|
auth/billing-not-enabled |
Cette fonctionnalité nécessite l'activation de la facturation. |
auth/invalid-display-name |
Le champ "displayName" doit être une chaîne valide. |
auth/invalid-name |
Le nom de ressource fourni n'est pas valide. |
auth/invalid-page-token |
Le jeton de page doit être une chaîne valide non vide. |
auth/invalid-project-id |
Projet parent non valide. Architecture mutualisée non activée dans le projet parent. |
auth/invalid-tenant-id |
L'ID de locataire doit être une chaîne non vide valide. |
auth/mismatching-tenant-id |
L'ID de locataire d'utilisateur ne correspond pas à l'ID de locataire TenantAwareAuth actuel. |
auth/missing-display-name |
Il manque un nom à afficher valide à la ressource en cours de création ou de modification. |
auth/insufficient-permission |
L'utilisateur n'est pas autorisé à accéder à la ressource demandée ou à exécuter l'opération de locataire spécifique. |
auth/quota-exceeded |
Le quota du projet pour l'opération spécifiée a été dépassé. |
auth/tenant-not-found |
Aucun locataire ne correspond à l'identifiant fourni. |
auth/unsupported-tenant-operation |
Cette opération n'est pas acceptée dans un contexte mutualisé. |
auth/invalid-testing-phone-number |
Un numéro de téléphone de test ou un code de test non valides ont été fournis. |
auth/test-phone-number-limit-exceeded |
Le nombre maximal de numéros de téléphone et de paires de code de test autorisé a été dépassé. |