Mengelola tenant Identity Platform secara terprogram

Dokumen ini menjelaskan cara menggunakan Identity Platform Admin SDK untuk mengelola tenant dan penggunanya secara terprogram. Beberapa aktivitas yang dapat Anda lakukan sebagai admin meliputi:

  • Pengelolaan pengguna: Membuat, memperbarui, menghapus, dan mencantumkan pengguna untuk tenant tertentu.

  • Verifikasi identitas: Mengidentifikasi pengguna aplikasi untuk membatasi akses ke resource di server Anda sendiri.

  • Impor pengguna: Memigrasikan pengguna dari sistem autentikasi eksternal atau project atau tenant Identity Platform lainnya.

  • Kontrol akses dengan klaim kustom: Tentukan atribut kustom di akun pengguna untuk tenant tertentu dan terapkan berbagai strategi kontrol akses, seperti kontrol akses berbasis peran.

  • Pengelolaan sesi pengguna: Mencabut token refresh pengguna untuk tenant tertentu.

  • Link tindakan email: Buat link email yang disesuaikan untuk reset sandi, login dengan link email, dan verifikasi email bagi pengguna tenant tertentu.

  • Pengelolaan tenant: Membuat, mencantumkan, mendapatkan, memperbarui, menghapus tenant untuk project Identity Platform tertentu.

  • Mengelola penyedia OIDC dan SAML di tenant: Mengelola konfigurasi OIDC dan SAML secara terprogram di tenant yang ditentukan.

Sebelum memulai

Fitur yang didukung

Tabel berikut mencantumkan fitur yang didukung oleh setiap SDK di lingkungan multi-tenant:

Fitur Node.js Java Python Go C#
Pembuatan token kustom
Memverifikasi token ID
Mengelola pengguna
Mengontrol akses dengan klaim kustom
Mencabut token refresh
Mengimpor pengguna
Membuat link tindakan email
Autentikasi multi-faktor
Mengelola konfigurasi penyedia SAML/OIDC
Pengelolaan cookie sesi

Tabel berikut menunjukkan metode login yang dapat Anda konfigurasikan menggunakan Admin SDK dan konsol Google Cloud dalam konteks khusus tenant:

Fitur Konsol Google Cloud Admin SDK
Email
OIDC
SAML
Sosial
Telepon
Autentikasi multi-faktor
Anonim

Pengelolaan tenant

Dengan Admin SDK, Anda dapat mengelola tenant secara terprogram dari lingkungan server yang aman, bukan menggunakan konsol Google Cloud. Hal ini termasuk kemampuan untuk membuat, mencantumkan, mendapatkan, mengubah, atau menghapus tenant.

Setiap tenant berisi penyedia identitas, setelan, dan kumpulan penggunanya sendiri. Operasi pengelolaan konfigurasi tenant (CRUD) tersedia dari instance project induk menggunakan admin.auth().tenantManager().

Konfigurasi tenant memberikan informasi tentang tenant, seperti nama tampilan, ID tenant, dan konfigurasi autentikasi email.

Semua setelan lainnya (seperti domain yang diizinkan dan URI pengalihan yang diautentikasi) dari tenant diwarisi dari project induk. Hal ini harus dikelola menggunakan konsol Google Cloud.

Untuk operasi seperti pengelolaan pengguna khusus tenant, mengonfigurasi penyedia OIDC/SAML, dan pembuatan link email, Anda memerlukan instance TenantAwareAuth untuk tenant target (diidentifikasi oleh tenantId uniknya).

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

Semua panggilan ke API pengelolaan pengguna, API pengelolaan penyedia OIDC/SAML, dan API pembuatan link email akan berada dalam cakupan tenant ini (menggunakan instance TenantAwareAuth-nya).

Mendapatkan tenant yang ada

Admin SDK menyediakan metode getTenant(), yang mengambil informasi tentang tenant berdasarkan tenantId-nya (ID unik untuk tenant).

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

Metode ini menampilkan objek Tenant yang sesuai dengan tenantId. Jika tenantId yang diberikan bukan milik tenant yang ada, promise yang ditampilkan akan menolak dengan error auth/tenant-not-found.

Berhati-hatilah agar tidak tertukar antara instance Tenant dengan objek TenantAwareAuth. authInstance.tenantManager().authForTenant() menampilkan instance TenantAwareAuth yang memperluas BaseAuth. Class Auth juga memperluas BaseAuth. BaseAuth menyediakan API untuk mengelola pengguna, mengonfigurasi penyedia OIDC/SAML dalam konteks yang berbeda. Untuk Auth, konteksnya berada di tingkat project induk. Untuk TenantAwareAuth, konteksnya berada di tingkat tenant (tenant ditentukan oleh ID tenant). Metode getTenant() akan di-resolve dengan informasi tenant dasar (seperti ID tenant, nama tampilan, dan setelan penyedia email), tetapi untuk memanggil API di tenant tersebut, Anda harus menggunakan authForTenant(tenantFromGetTenant.tenantId).

Membuat tenant

Gunakan metode createTenant() untuk membuat konfigurasi tenant baru:

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

Anda dapat memberikan kombinasi properti berikut:

Properti Jenis Deskripsi
displayName
string
    
Nama tampilan tenant. Nama ini harus terdiri dari 4-20 karakter, yang terdiri dari huruf, angka, dan tanda hubung, dan harus diawali dengan huruf.
emailSignInConfig
{
  enable: boolean,
  passwordRequired: boolean
}
    
Konfigurasi penyedia login dengan email. Hal ini mencakup apakah penyedia email diaktifkan, dan apakah sandi diperlukan untuk login dengan email. Jika tidak diperlukan, login dengan email dapat dilakukan dengan sandi atau menggunakan login dengan link email.
multiFactorConfig
{
  state: 'DISABLED' | 'ENABLED',
  factorIds: string[]
}
    
Apakah autentikasi multi-faktor diaktifkan untuk tenant, dan jenis faktor apa yang diizinkan. Saat ini, satu-satunya ID faktor yang didukung adalah phone.
testPhoneNumbers
{
  string: string
}
  
Peta nomor telepon dan kode autentikasi multi-faktor terkait untuk mendaftar untuk tujuan pengujian. Maksimum 10 entri yang diizinkan. Untuk menghapus semua nomor telepon pengujian, tetapkan kolom ini ke null.

Metode ini menampilkan objek Tenant untuk tenant yang baru dibuat.

Memperbarui tenant

Gunakan metode updateTenant() untuk mengubah data tenant yang ada. Anda harus menentukan tenantId, beserta properti yang akan diperbarui untuk tenant tersebut.

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() menerima properti yang sama dengan createTenant(). Semua properti bersifat opsional. Jika properti tidak ditentukan, nilai yang ada tidak akan diubah.

Metode ini menampilkan objek Tenant yang diperbarui setelah selesai. Jika tenantId yang diberikan bukan milik tenant yang ada, promise yang ditampilkan akan ditolak dengan error auth/tenant-not-found.

Menghapus tenant

Anda dapat menghapus tenant menggunakan tenantId-nya:

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

Metode ini menampilkan hasil kosong saat penghapusan berhasil dilakukan. Jika tenantId yang diberikan bukan milik tenant yang ada, promise yang ditampilkan akan menolak dengan error auth/tenant-not-found.

Mencantumkan tenant

Gunakan metode listTenants() untuk mencantumkan tenant yang ada:

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

Setiap batch hasil berisi daftar tenant, ditambah token halaman berikutnya untuk menampilkan daftar batch tenant berikutnya. Setelah semua tenant sudah tercantum, tidak ada pageToken yang ditampilkan.

Jika kolom maxResults tidak ditentukan, nilai defaultnya adalah 1.000 tenant per batch. Angka ini juga menunjukkan jumlah maksimum tenant yang diizinkan untuk dicantumkan pada satu waktu. Setiap nilai yang lebih besar dari nilai maksimum akan menampilkan error argumen. Jika pageToken tidak ditentukan, metode akan mencantumkan tenant dari awal.

Mengelola penyedia SAML dan OIDC secara terprogram

Admin SDK menyediakan API untuk mengelola konfigurasi penyedia Security Assertion Markup Language (SAML) 2.0 dan OpenID Connect (OIDC) secara terprogram dari lingkungan server yang aman.

Dengan Admin SDK, Anda dapat mengelola penyedia ini untuk tenant tertentu. Hal ini mirip dengan mengelola penyedia OIDC dan SAML tingkat project.

Untuk mengelola penyedia bagi tenant, buat instance TenantAwareAuth terlebih dahulu:

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

Kemudian, Anda dapat melakukan operasi umum, seperti membuat, mengubah, atau menghapus penyedia untuk tenant.

Membuat penyedia

Kode berikut menunjukkan cara membuat penyedia SAML untuk tenant:

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

Mengubah penyedia

Kode berikut menunjukkan cara memodifikasi penyedia:

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

Mendapatkan penyedia

Kode berikut menunjukkan cara mengambil konfigurasi penyedia untuk tenant tertentu menggunakan ID penyedianya:

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

Penyedia listingan

Kode berikut menunjukkan cara mencantumkan konfigurasi penyedia untuk tenant tertentu:

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

Menghapus penyedia

Kode berikut menunjukkan cara menghapus penyedia:

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

Penyedia OIDC dikelola dengan cara yang sama seperti penyedia OIDC level project, kecuali penyedia tersebut dapat dikelola dari instance TenantAwareAuth yang sesuai, bukan instance level project Auth.

Untuk mempelajari lebih lanjut, lihat Mengelola penyedia SAML dan OIDC secara terprogram.

Mengelola pengguna khusus tenant

Anda dapat menggunakan Admin SDK untuk membuat, mengambil, memperbarui, menghapus, dan mencantumkan semua pengguna untuk tenant tertentu.

Untuk memulai, Anda memerlukan instance TenantAwareAuth untuk tenant yang sesuai:

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

Mendapatkan pengguna

Anda dapat mengambil pengguna khusus tenant dengan ID 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());

Anda juga dapat mengidentifikasi pengguna berdasarkan emailnya:

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

Membuat pengguna

Gunakan metode createUser() untuk membuat pengguna baru bagi tenant tertentu. Saat membuat pengguna baru, memberikan uid bersifat opsional; jika tidak ditentukan, Identity Platform akan menyediakan ID unik.

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

Mengubah pengguna

Anda dapat mengubah pengguna yang ada dengan menentukan uid mereka ke metode 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());

Menghapus pengguna

Contoh berikut menunjukkan cara menghapus pengguna berdasarkan uid-nya:

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

Menampilkan daftar pengguna

Untuk mengambil seluruh daftar pengguna untuk tenant tertentu dalam batch, gunakan metode listUsers(). Setiap batch akan berisi daftar data pengguna, ditambah token halaman berikutnya jika masih ada pengguna tambahan.

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

Lihat dokumentasi Admin SDK tentang mengelola pengguna untuk mempelajari lebih lanjut.

Mengimpor pengguna

Anda dapat menggunakan Admin SDK untuk mengimpor pengguna secara massal ke tenant tertentu dengan hak istimewa yang ditingkatkan. Hal ini menawarkan banyak manfaat, seperti kemampuan untuk memigrasikan pengguna dari produk Identity Platform lain, dari tenant lain, atau dari sistem autentikasi eksternal menggunakan algoritma hashing yang berbeda. Anda juga dapat mengimpor pengguna dengan penyedia gabungan (seperti SAML dan OIDC) dan klaim kustom secara langsung secara massal.

Untuk memulai, dapatkan instance TenantAwareAuth untuk tenant yang sesuai:

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

Anda dapat mengimpor hingga 1.000 pengguna sekaligus menggunakan algoritma hashing tertentu.

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

Semua pengguna yang diimpor akan memiliki tenantId yang ditetapkan ke tenantAuth.tenantId.

Pengguna tanpa sandi juga dapat diimpor ke tenant tertentu. Pengguna ini dapat diimpor dengan penyedia gabungan dan klaim kustom.

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

Lihat Mengimpor pengguna di dokumentasi Admin SDK untuk mempelajari lebih lanjut.

Verifikasi identitas

Saat aplikasi klien Identity Platform berkomunikasi dengan server backend khusus, pengguna yang saat ini login harus diidentifikasi di server tersebut. Hal ini dapat dilakukan dengan aman dengan mengirimkan token ID pengguna setelah berhasil login menggunakan koneksi aman ke server Anda. Server kemudian dapat memverifikasi integritas dan keaslian token ID.

Admin SDK memiliki metode bawaan untuk memverifikasi dan mendekode token ID untuk tenant tertentu.

Setelah berhasil memproses login pengguna ke tenant tertentu dari klien, ambil token ID pengguna menggunakan Client SDK:

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

Buat instance TenantAwareAuth di server:

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

Kemudian, Anda dapat memverifikasi token ID untuk tenant tertentu tersebut:

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

Resource sisi server mungkin dapat diakses oleh beberapa tenant dengan tingkat akses yang berbeda. Karena ID tenant mungkin tidak diketahui sebelumnya dalam kasus ini, token ID dapat diverifikasi di tingkat project terlebih dahulu.

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

Lihat dokumentasi Admin SDK tentang memverifikasi token ID untuk mempelajari lebih lanjut.

Mengelola sesi pengguna

Sesi Identity Platform berumur panjang. Setiap kali pengguna login, kredensial pengguna tersebut diverifikasi di server Identity Platform, lalu ditukar dengan token ID berumur pendek dan token refresh berumur panjang. Token ID berlaku selama satu jam. Token refresh tidak pernah berakhir masa berlakunya, kecuali jika pengguna dinonaktifkan, dihapus, atau mengalami perubahan akun besar (seperti pembaruan email atau sandi).

Terkadang, token refresh pengguna mungkin perlu dicabut karena alasan keamanan, seperti pengguna melaporkan perangkat yang hilang atau dicuri, penemuan kerentanan umum dalam aplikasi, atau kebocoran token aktif dalam skala besar. Admin SDK menyediakan API untuk mencabut semua token refresh yang dikeluarkan untuk pengguna tertentu dari tenant tertentu.

Untuk memulai, Anda memerlukan 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");

Token refresh kemudian dapat dicabut dengan menentukan uid pengguna tersebut:

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

Setelah token refresh dicabut, tidak ada token ID baru yang dapat dikeluarkan untuk pengguna tersebut hingga mereka melakukan autentikasi ulang. Namun, token ID yang ada akan tetap aktif hingga waktu habis masa berlakunya (satu jam).

Anda dapat memverifikasi bahwa token ID valid yang belum habis masa berlakunya tidak dicabut dengan menentukan parameter checkRevoked opsional; hal ini memeriksa apakah token dicabut setelah integritas dan autentikannya diverifikasi.

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

Lihat dokumentasi Admin SDK tentang mengelola sesi untuk mempelajari lebih lanjut.

Mengontrol akses dengan klaim kustom

Admin SDK mendukung penetapan atribut kustom pada akun pengguna untuk tenant tertentu. Atribut ini memungkinkan Anda menerapkan berbagai strategi kontrol akses, seperti kontrol akses berbasis peran. Atribut ini dapat digunakan untuk memberi pengguna berbagai tingkat akses yang diterapkan oleh aturan keamanan aplikasi.

Untuk memulai, dapatkan instance TenantAwareAuth untuk tenant yang sesuai:

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

Klaim kustom dapat berisi data sensitif, sehingga sebaiknya hanya ditetapkan dari lingkungan server dengan hak istimewa menggunakan Admin SDK.

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.

Atribut kustom yang baru ditetapkan akan muncul di atribut tingkat teratas payload token saat pengguna login atau memuat ulang token ID-nya di sesi yang ada. Dalam contoh sebelumnya, token ID berisi klaim tambahan: {admin: true}.

Setelah memverifikasi token ID dan mendekode payload-nya, klaim kustom tambahan dapat diperiksa untuk menerapkan kontrol akses.

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

Klaim kustom untuk pengguna yang ada untuk tenant tertentu juga tersedia sebagai properti pada data pengguna.

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

Lihat dokumentasi Admin SDK tentang Klaim kustom untuk mempelajari lebih lanjut.

Dengan menggunakan SDK Klien Identity Platform, Anda dapat mengirim email kepada pengguna tenant tertentu yang berisi link yang dapat mereka gunakan untuk reset sandi, verifikasi alamat email, dan login dengan email. Email ini dikirim oleh Google dan memiliki kemampuan penyesuaian yang terbatas.

Dengan Admin SDK, Anda dapat membuat link ini secara terprogram dalam cakupan tenant tertentu.

Untuk memulai, dapatkan instance TenantAwareAuth untuk tenant yang sesuai:

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

Contoh berikut menunjukkan cara membuat link untuk memverifikasi email pengguna untuk tenant yang ditentukan:

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

Mekanisme serupa tersedia untuk membuat link reset sandi dan login berbasis email. Perhatikan bahwa saat membuat link tindakan email dalam konteks tenant, ID tenant harus diuraikan dari link dan ditetapkan pada instance Auth klien sebelum kode dapat diterapkan.

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

Lihat Link tindakan email dalam dokumentasi Admin SDK untuk mempelajari lebih lanjut.

Pesan error

Tabel berikut mencantumkan pesan error umum yang mungkin Anda temui.

Kode error Deskripsi dan Langkah Penyelesaian
auth/billing-not-enabled Fitur ini memerlukan pengaktifan penagihan.
auth/invalid-display-name Kolom displayName harus berupa string yang valid.
auth/invalid-name Nama resource yang diberikan tidak valid.
auth/invalid-page-token Token halaman harus berupa string tidak kosong yang valid.
auth/invalid-project-id Project induk tidak valid. Project induk tidak mengaktifkan, atau tidak pernah mengaktifkan, multi-tenancy.
auth/invalid-tenant-id ID tenant harus berupa string yang valid dan tidak kosong.
auth/mismatching-tenant-id ID tenant pengguna tidak cocok dengan ID tenant TenantAwareAuth saat ini.
auth/missing-display-name Resource yang dibuat atau diedit tidak memiliki nama tampilan yang valid.
auth/insufficient-permission Pengguna tidak memiliki izin yang memadai untuk mengakses resource yang diminta atau menjalankan operasi tenant tertentu.
auth/quota-exceeded Kuota project untuk operasi yang ditentukan telah terlampaui.
auth/tenant-not-found Tidak ada tenant yang sesuai dengan ID yang diberikan.
auth/unsupported-tenant-operation Operasi ini tidak didukung dalam konteks multi-tenant.
auth/invalid-testing-phone-number Nomor telepon pengujian atau kode pengujian yang diberikan tidak valid.
auth/test-phone-number-limit-exceeded Jumlah maksimum pasangan kode dan nomor telepon pengujian yang diizinkan telah terlampaui.