Administra grupos de usuarios de Identity Platform de manera programática

En este documento, se explica cómo usar el SDK de Admin de Identity Platform para administrar grupos de usuarios y sus usuarios de manera programática. Entre las actividades que puedes realizar como administrador, se incluyen las siguientes:

  • Administración de usuarios: Crea, actualiza, borra y enumera usuarios para un grupo de usuarios específico.

  • Verificación de identidad: Identifica los usuarios de una app para restringir el acceso a los recursos en tu propio servidor.

  • Importar usuarios: migra usuarios desde un sistema de autenticación externo o desde otro proyecto o grupo de usuarios de Identity Platform.

  • Control de acceso con reclamaciones personalizadas: Define atributos personalizados en cuentas de usuario para un grupo de usuarios específico y, luego, implementa varias estrategias de control de acceso, como el control de acceso basado en funciones.

  • Administración de sesiones de usuario: Revoca los tokens de actualización de un usuario para un grupo de usuarios específico.

  • Vínculos de acción de correo electrónico: genera vínculos de correo electrónico personalizados para restablecer la contraseña, el acceso mediante vínculos de correo electrónico y la verificación de correos electrónicos para usuarios de un grupo de usuarios específico.

  • Administración de grupos de usuarios: crea, enumera, obtén, actualiza y borra grupos de usuarios para un proyecto específico de Identity Platform.

  • Administra proveedores OIDC y SAML en grupos de usuarios: administra de forma programática configuraciones de OIDC y SAML en un grupo de usuarios específico.

Antes de comenzar

Funciones admitidas

En la siguiente tabla, se enumeran las características compatibles con cada SDK en un entorno de grupos de usuarios múltiples:

Función Node.js Java Python Go C#
Creación de tokens personalizados
Verifica tokens de ID
Administra usuarios.
Cómo controlar el acceso con reclamaciones personalizadas
Revocar tokens de actualización
Importar usuarios
Generar vínculos de acciones de correo electrónico
Autenticación de varios factores
Administra configuraciones del proveedor SAML/OIDC
Administración de cookies de sesión

En la siguiente tabla, se muestran los métodos de acceso que puedes configurar mediante el SDK de Admin y la consola de Google Cloud en un contexto de instancia específico:

Atributo Consola de Google Cloud SDK de Admin
Correo electrónico
OIDC
SAML
Social
Teléfono
Autenticación de varios factores
Anónimo

Administración de grupos de usuarios

Con el SDK de Admin, puedes administrar grupos de usuarios de manera programática desde un entorno de servidor seguro en lugar de usar la consola de Google Cloud. Esto incluye la capacidad de crear, enumerar, obtener, modificar o borrar grupos de usuarios.

Cada grupo de usuarios contiene sus propios proveedores de identidad, configuración y grupos de usuarios. Las operaciones de administración de configuración de grupos de usuarios (CRUD) están disponibles en la instancia del proyecto superior mediante admin.auth().tenantManager().

Una configuración de grupos de usuarios proporciona información sobre el grupo de usuarios, como su nombre comercial, identificador y configuración de autenticación de correo electrónico.

Todas las demás configuraciones (como los dominios incluidos en la lista blanca y los URI de redireccionamiento autenticados) de una instancia se heredan del proyecto superior. Estos se deben administrar mediante la consola de Google Cloud.

Para operaciones como la administración de usuarios específicos de grupos de usuarios, la configuración de proveedores OIDC/SAML y la generación de vínculos de correo electrónico, necesitarás una instancia TenantAwareAuth para el grupo de usuarios de destino (identificado por su tenantId único).

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);

Todas las llamadas a las API de administración de usuarios, las API de administración de proveedores OIDC/SAML y las API de generación de vínculos de correo electrónico estarán dentro del alcance de este grupo de usuarios (mediante su instancia TenantAwareAuth).

Cómo obtener un grupo de usuarios existente

El SDK de Admin proporciona el método getTenant(), que recupera información sobre un grupo de usuarios según su tenantId (un identificador único del grupo de usuarios).

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());

Mediante este método, se muestra un objeto Tenant correspondiente a tenantId. Si el tenantId proporcionado no pertenece a una instancia existente, la promesa mostrada se rechaza con un error auth/tenant-not-found.

Ten cuidado de no confundir una instancia Tenant con un objeto TenantAwareAuth. authInstance.tenantManager().authForTenant() muestra una instancia TenantAwareAuth que extiende BaseAuth. La clase Auth también extiende BaseAuth. BaseAuth proporciona API para administrar usuarios y configurar OIDC/SAML en diferentes contextos. En el caso de Auth, el contexto está en el nivel del proyecto superior. En TenantAwareAuth, el contexto se encuentra a nivel de la instancia (la instancia se determina mediante el ID de la instancia). El método getTenant() se resolverá con información básica de la instancia (como el ID de la instancia, el nombre visible y la configuración del proveedor de correo electrónico). Sin embargo, para llamar a las API de esa instancia, debes usar authForTenant(tenantFromGetTenant.tenantId).

Crea un grupo de usuarios

Usa el método createTenant() para crear una configuración de grupo de usuarios nueva:

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());

Puedes proporcionar cualquier combinación de estas propiedades:

Property Tipo Descripción
displayName
string
    
El nombre comercial de la instancia. Debe tener entre 4 y 20 caracteres, contener letras, dígitos y guiones, y comenzar con una letra.
emailSignInConfig
{
  enable: boolean,
  passwordRequired: boolean
}
    
La configuración del proveedor de acceso por correo electrónico. Esto incluye si el proveedor de correo electrónico está habilitado y si se requiere una contraseña para acceder por correo electrónico. Cuando no se requiere, el acceso por correo electrónico se puede realizar con una contraseña o mediante el acceso con un vínculo por correo electrónico.
multiFactorConfig
{
  state: 'DISABLED' | 'ENABLED',
  factorIds: string[]
}
    
Si la autenticación de varios factores está habilitada para la instancia y qué tipos de factores están permitidos. En la actualidad, el único ID de factor admitido es phone.
testPhoneNumbers
{
  string: string
}
  
Un mapa de números de teléfono y sus códigos de autenticación de varios factores asociados para registrarse con propósitos de prueba. Se permite un máximo de 10 entradas. Para quitar todos los números de teléfono de prueba, configura este campo como null.

El método muestra un objeto Tenant para el grupo de usuarios recién creado.

Actualiza un grupo de usuarios

Usa el método updateTenant() para modificar los datos de un grupo de usuarios existente. Deberás especificar el tenantId, junto con las propiedades que deseas actualizar para ese grupo de usuarios.

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() acepta las mismas propiedades que createTenant(). Todas las propiedades son opcionales. Si no se especifica una propiedad, el valor existente no se modificará.

Mediante el método, se muestra un objeto Tenant actualizado una vez que se completa. Si el tenantId proporcionado no pertenece a una instancia existente, la promesa mostrada se rechaza con un error auth/tenant-not-found.

Borra un grupo de usuarios

Puedes borrar un grupo de usuarios con su 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);

Mediante el método, se muestra un resultado vacío cuando la eliminación se completa de forma correcta. Si el tenantId proporcionado no pertenece a una instancia existente, la promesa mostrada se rechaza con un error auth/tenant-not-found.

Enumera grupos de usuarios

Usa el método listTenants() para enumerar los grupos de usuarios existentes:

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());
}

Cada lote de resultados contiene una lista de grupos de usuarios, más un token de página siguiente para enumerar el siguiente lote de grupos de usuarios. Cuando ya se enumeraron todos los grupos de usuarios, no se muestra ningún pageToken.

Si no se especifica un campo maxResults, el valor predeterminado es 1,000 grupos de usuarios por lote. Esta es también la cantidad máxima de grupos de usuarios que se pueden mostrar a la vez. Cualquier valor superior al máximo arrojará un error de argumento. Si no se especifica pageToken, el método mostrará una lista de grupos de usuarios desde el principio.

Administra proveedores SAML y OIDC de manera programática

El SDK de Admin proporciona las API para administrar configuraciones de proveedores de lenguaje de marcado de confirmación de seguridad (SAML) 2.0 y OpenID Connect (OIDC) de manera programática desde un entorno de servidor seguro.

Con el SDK de Admin, puedes administrar estos proveedores para una instancia específica. Esto es similar a la administración de proveedores de OIDC y SAML a nivel de proyecto.

Para administrar los proveedores de un grupo de usuarios, primero crea una instancia 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");

Luego, puedes realizar operaciones comunes, como crear, modificar o borrar proveedores para un grupo de usuarios.

Crea un proveedor

El siguiente código muestra cómo crear un proveedor de SAML para un grupo de usuarios:

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());

Modifica un proveedor

En el siguiente código, se muestra cómo modificar un proveedor:

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());

Obtén un proveedor

En el siguiente código, se muestra cómo recuperar la configuración del proveedor para un grupo de usuarios específico con su ID del proveedor:

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());

Enumera proveedores

En el siguiente código, se muestra cómo enumerar las configuraciones de proveedores para un grupo de usuarios determinado:

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());
}

Borra un proveedor

En el siguiente código, se muestra cómo borrar un proveedor:

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");

Los proveedores de OIDC se administran de manera similar a los proveedores de OIDC a nivel de proyecto, excepto que se pueden administrar desde la instancia TenantAwareAuth correspondiente, en lugar de una instancia a nivel de proyecto Auth.

Para obtener más información, consulta Administra los proveedores de SAML y OIDC de manera programática.

Administra usuarios específicos de un grupo de usuarios

Puedes usar el SDK de Admin para crear, recuperar, actualizar, borrar y enumerar todos los usuarios de un grupo de usuarios específico.

Para comenzar, necesitas una instancia TenantAwareAuth para el grupo de usuarios correspondiente:

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");

Obtén un usuario

Puedes recuperar un usuario específico del grupo de usuarios con un identificador 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());

También puedes identificar a un usuario mediante su correo electrónico:

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());

Crea un usuario

Usa el método createUser() a fin de crear usuarios nuevos para una instancia específica. Cuando se crea un usuario nuevo, proporcionar un uid es opcional. Si no se especifica, Identity Platform aprovisionará uno único.

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());

Modifica a un usuario

Puedes modificar los usuarios existentes si especificas sus uid en el método 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());

Borra un usuario

En el siguiente ejemplo, se muestra cómo borrar un usuario por su 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);

Enumera los usuarios

Para recuperar una lista completa de usuarios de una instancia específica en lotes, usa el método listUsers(). Cada lote contendrá una lista de registros de usuarios y un token de página siguiente, si quedan usuarios adicionales.

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();
}

Consulta la documentación del SDK de Admin sobre la administración de usuarios para obtener más información.

Importa usuarios

Puedes usar el SDK de Admin para importar usuarios de forma masiva en una instancia específica con privilegios elevados. Esto ofrece numerosos beneficios, como la capacidad de migrar usuarios desde otro producto de Identity Platform, desde otra instancia o desde un sistema de autenticación externo mediante el uso de un algoritmo de hashing diferente. También puedes importar usuarios con proveedores federados (como SAML y OIDC) y reclamaciones personalizadas directamente de forma masiva.

Para comenzar, obtén una instancia TenantAwareAuth para el grupo de instancias correspondiente:

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");

Puedes importar hasta 1,000 usuarios a la vez con un algoritmo de hashing específico.

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());
}

Todos los usuarios importados tendrán su tenantId configurado como tenantAuth.tenantId.

Los usuarios sin contraseñas también se pueden importar a una instancia específica. Estos usuarios se pueden importar con proveedores federados y reclamaciones personalizadas.

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());
}

Consulta Importa usuarios en la documentación del SDK de Admin para obtener más información.

Verificación de identidad

Cuando una app cliente de Identity Platform se comunica con un servidor de backend personalizado, el usuario activo actual debe identificarse en ese servidor. Esto se puede hacer de forma segura mediante el envío del token de ID del usuario después del acceso exitoso mediante una conexión segura a tu servidor. Luego, el servidor puede verificar la integridad y la autenticidad del token de ID.

El SDK de Admin tiene un método integrado para verificar y decodificar tokens de ID para un grupo de usuarios específico.

Después de acceder correctamente un usuario a un grupo de usuarios específico del cliente, recupera el token de ID del usuario con el SDK de cliente:

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.
  });

Crea una instancia TenantAwareAuth en el servidor:

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");

Luego, puedes verificar el token de ID para ese grupo de usuarios específico:

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
  });

Varios grupos de usuarios con diferentes niveles de acceso pueden acceder a un recurso del servidor. Dado que es posible que el ID del grupo de usuarios no se conozca con anticipación en este caso, el token de ID se puede verificar primero a nivel de proyecto.

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());
}

Consulta el artículo del SDK de Admin Verifica tokens de ID para obtener más información.

Administra sesiones de usuarios

Las sesiones de Identity Platform son de larga duración. Cada vez que un usuario accede, sus credenciales se verifican en el servidor de Identity Platform y, luego, se intercambian por un token de ID de corta duración y un token de actualización de larga duración. Los tokens de ID tienen una duración de una hora. Los tokens de actualización no vencen, excepto cuando se inhabilita un usuario, se lo borra o experimenta un cambio importante en la cuenta (como una actualización de correo electrónico o de contraseña).

En algunos casos, puede ser necesario revocar el token de actualización de un usuario por razones de seguridad, como cuando un usuario informa un dispositivo perdido o robado, cuando se descubre una vulnerabilidad general dentro de una app o cuando se produce una pérdida general de tokens activos. El SDK de Admin proporciona una API para revocar todos los tokens de actualización emitidos para un usuario específico de una instancia específica.

Para comenzar, necesitas una instancia 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");

Los tokens de actualización se pueden revocar mediante la especificación del uid de ese usuario:

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)");

Después de que se revocan los tokens de actualización, no se pueden emitir tokens de ID nuevos para ese usuario hasta que se vuelvan a autenticar. Sin embargo, los tokens de ID existentes permanecerán activos hasta su fecha de vencimiento natural (una hora).

Puedes verificar que un token de ID válido que no haya vencido no se haya revocado con la especificación del parámetro opcional checkRevoked. Para ello, verifica si se revoca un token después de que se verifica su integridad y autenticidad.

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
  }
}

Consulta la documentación del SDK de Admin sobre la administración de sesiones para obtener más información.

Cómo controlar el acceso con reclamaciones personalizadas

El SDK de Admin admite la definición de atributos personalizados en las cuentas de usuario de una instancia específica. Estos atributos te permiten implementar diferentes estrategias de control de acceso, como el control de acceso basado en funciones. Los atributos se pueden usar para otorgar a los usuarios diferentes niveles de acceso que aplican las reglas de seguridad de la aplicación.

Para comenzar, obtén una instancia TenantAwareAuth para el grupo de usuarios correspondiente:

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");

Las reclamaciones personalizadas pueden contener datos sensibles, por lo que solo deben configurarse desde un entorno de servidor con privilegios mediante el SDK de 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.

Los nuevos atributos personalizados aparecerán en los atributos de nivel superior de la carga útil del token la próxima vez que el usuario acceda o actualice sus tokens de ID en una sesión existente. En el ejemplo anterior, el token de ID contiene una reclamación adicional: {admin: true}.

Después de verificar el token de ID y decodificar su carga útil, se pueden verificar las reclamaciones personalizadas adicionales para que se aplique el control de acceso.

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.
}

Las reclamaciones personalizadas para un usuario existente de un grupo de usuarios específico también están disponibles como propiedad en el registro del usuario.

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"));

Consulta la documentación del SDK de Admin sobre las reclamaciones personalizadas para obtener más información.

Con los SDK de cliente de Identity Platform, puedes enviar a los usuarios de un correo electrónico de grupo de usuarios específico que contiene vínculos que pueden usar para el restablecimiento de contraseñas, la verificación de direcciones de correo electrónico y el acceso a servicios mediante correo electrónico. Google envía estos mensajes, que cuentan con personalización limitada.

Con el SDK de Admin, puedes generar estos vínculos de manera programática dentro del alcance de un grupo de usuarios específico.

Para comenzar, obtén una instancia TenantAwareAuth para el grupo de usuarios correspondiente:

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");

En el siguiente ejemplo, se muestra cómo generar un vínculo para verificar el correo electrónico de un usuario para un grupo de usuarios específico:

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);

Hay mecanismos similares disponibles para generar vínculos de restablecimiento de contraseñas y de acceso mediante correo electrónico. Ten en cuenta que, cuando se genera un vínculo de acción por correo electrónico en el contexto de una instancia, el ID de la instancia debe analizarse desde el vínculo y configurarse en la instancia Auth del cliente antes de que se pueda aplicar el código.

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.
  });

Consulta los vínculos de acción por correo electrónico en la documentación del SDK de Admin para obtener más información.

Mensajes de error

En la siguiente tabla, se enumeran los mensajes de error comunes que puedes encontrarte.

Código de error Descripción y pasos de resolución
auth/billing-not-enabled Es necesario habilitar la facturación para usar esta función.
auth/invalid-display-name El campo displayName debe ser una string válida.
auth/invalid-name El nombre del recurso proporcionado no es válido.
auth/invalid-page-token El token de la página debe ser una string válida que no esté vacía.
auth/invalid-project-id Proyecto superior no válido. El proyecto superior no habilita los grupos de usuarios múltiples o no los habilitó.
auth/invalid-tenant-id El ID del grupo de usuarios debe ser una string válida que no esté vacía.
auth/mismatching-tenant-id El ID del grupo de usuarios no coincide con el ID del grupo de usuarios TenantAwareAuth actual.
auth/missing-display-name Falta un nombre visible válido para el recurso que se crea o edita.
auth/insufficient-permission El usuario no tiene suficientes permisos para acceder al recurso solicitado o ejecutar la operación de instancia específica.
auth/quota-exceeded Se superó la cuota del proyecto para la operación especificada.
auth/tenant-not-found No hay una instancia correspondiente al identificador proporcionado.
auth/unsupported-tenant-operation Esta operación no se admite en un contexto de varias instancias.
auth/invalid-testing-phone-number Se proporcionó un número de teléfono de prueba o un código de prueba que no es válido.
auth/test-phone-number-limit-exceeded Se excedió la cantidad máxima de pares de código y número de teléfono de prueba permitidos.