diff --git a/etc/firebase-admin.api.md b/etc/firebase-admin.api.md index 3941798ebd..38981491e2 100644 --- a/etc/firebase-admin.api.md +++ b/etc/firebase-admin.api.md @@ -251,6 +251,7 @@ export namespace auth { expiresIn: number; } export interface Tenant { + anonymousSignInEnabled: boolean; displayName?: string; emailSignInConfig?: { enabled: boolean; @@ -301,6 +302,7 @@ export namespace auth { photoURL?: string | null; } export interface UpdateTenantRequest { + anonymousSignInEnabled?: boolean; displayName?: string; emailSignInConfig?: EmailSignInProviderConfig; multiFactorConfig?: MultiFactorConfig; diff --git a/src/auth/index.ts b/src/auth/index.ts index a1ff346b97..f3a387393d 100644 --- a/src/auth/index.ts +++ b/src/auth/index.ts @@ -1014,6 +1014,11 @@ export namespace auth { passwordRequired?: boolean; }; + /** + * Whether the anonymous provider is enabled. + */ + anonymousSignInEnabled: boolean; + /** * The multi-factor auth configuration on the current tenant. */ @@ -1089,6 +1094,11 @@ export namespace auth { */ emailSignInConfig?: EmailSignInProviderConfig; + /** + * Whether the anonymous provider is enabled. + */ + anonymousSignInEnabled?: boolean; + /** * The multi-factor auth configuration to update on the tenant. */ diff --git a/src/auth/tenant.ts b/src/auth/tenant.ts index a7b1d188f4..392494739b 100644 --- a/src/auth/tenant.ts +++ b/src/auth/tenant.ts @@ -29,6 +29,7 @@ import UpdateTenantRequest = auth.UpdateTenantRequest; /** The corresponding server side representation of a TenantOptions object. */ export interface TenantOptionsServerRequest extends EmailSignInConfigServerRequest { displayName?: string; + enableAnonymousUser?: boolean; mfaConfig?: MultiFactorAuthServerConfig; testPhoneNumbers?: {[key: string]: string}; } @@ -39,6 +40,7 @@ export interface TenantServerResponse { displayName?: string; allowPasswordSignup?: boolean; enableEmailLinkSignin?: boolean; + enableAnonymousUser?: boolean; mfaConfig?: MultiFactorAuthServerConfig; testPhoneNumbers?: {[key: string]: string}; } @@ -50,6 +52,7 @@ export class Tenant implements TenantInterface { public readonly tenantId: string; public readonly displayName?: string; public readonly emailSignInConfig?: EmailSignInConfig; + public readonly anonymousSignInEnabled: boolean; public readonly multiFactorConfig?: MultiFactorAuthConfig; public readonly testPhoneNumbers?: {[phoneNumber: string]: string}; @@ -70,6 +73,9 @@ export class Tenant implements TenantInterface { if (typeof tenantOptions.displayName !== 'undefined') { request.displayName = tenantOptions.displayName; } + if (typeof tenantOptions.anonymousSignInEnabled !== 'undefined') { + request.enableAnonymousUser = tenantOptions.anonymousSignInEnabled; + } if (typeof tenantOptions.multiFactorConfig !== 'undefined') { request.mfaConfig = MultiFactorAuthConfig.buildServerRequest(tenantOptions.multiFactorConfig); } @@ -105,6 +111,7 @@ export class Tenant implements TenantInterface { const validKeys = { displayName: true, emailSignInConfig: true, + anonymousSignInEnabled: true, multiFactorConfig: true, testPhoneNumbers: true, }; @@ -179,6 +186,7 @@ export class Tenant implements TenantInterface { allowPasswordSignup: false, }); } + this.anonymousSignInEnabled = !!response.enableAnonymousUser; if (typeof response.mfaConfig !== 'undefined') { this.multiFactorConfig = new MultiFactorAuthConfig(response.mfaConfig); } @@ -193,6 +201,7 @@ export class Tenant implements TenantInterface { tenantId: this.tenantId, displayName: this.displayName, emailSignInConfig: this.emailSignInConfig?.toJSON(), + anonymousSignInEnabled: this.anonymousSignInEnabled, multiFactorConfig: this.multiFactorConfig?.toJSON(), testPhoneNumbers: this.testPhoneNumbers, }; diff --git a/test/integration/auth.spec.ts b/test/integration/auth.spec.ts index 1eb7bfe6a8..76eee8c85e 100644 --- a/test/integration/auth.spec.ts +++ b/test/integration/auth.spec.ts @@ -886,6 +886,7 @@ describe('admin.auth', () => { enabled: true, passwordRequired: true, }, + anonymousSignInEnabled: false, multiFactorConfig: { state: 'ENABLED', factorIds: ['phone'], @@ -901,6 +902,7 @@ describe('admin.auth', () => { enabled: false, passwordRequired: true, }, + anonymousSignInEnabled: false, multiFactorConfig: { state: 'DISABLED', factorIds: [], @@ -915,6 +917,7 @@ describe('admin.auth', () => { enabled: true, passwordRequired: false, }, + anonymousSignInEnabled: false, multiFactorConfig: { state: 'ENABLED', factorIds: ['phone'], @@ -957,6 +960,20 @@ describe('admin.auth', () => { }); }); + it('createTenant() can enable anonymous users', async () => { + const tenant = await admin.auth().tenantManager().createTenant({ + displayName: 'testTenantWithAnon', + emailSignInConfig: { + enabled: false, + passwordRequired: true, + }, + anonymousSignInEnabled: true, + }); + createdTenants.push(tenant.tenantId); + + expect(tenant.anonymousSignInEnabled).to.be.true; + }); + // Sanity check user management + email link generation + custom attribute APIs. // TODO: Confirm behavior in client SDK when it starts supporting it. describe('supports user management, email link generation, custom attribute and token revocation APIs', () => { @@ -1300,6 +1317,25 @@ describe('admin.auth', () => { }); }); + it('updateTenant() should be able to enable/disable anon provider', async () => { + const tenantManager = admin.auth().tenantManager(); + let tenant = await tenantManager.createTenant({ + displayName: 'testTenantUpdateAnon', + }); + createdTenants.push(tenant.tenantId); + expect(tenant.anonymousSignInEnabled).to.be.false; + + tenant = await tenantManager.updateTenant(tenant.tenantId, { + anonymousSignInEnabled: true, + }); + expect(tenant.anonymousSignInEnabled).to.be.true; + + tenant = await tenantManager.updateTenant(tenant.tenantId, { + anonymousSignInEnabled: false, + }); + expect(tenant.anonymousSignInEnabled).to.be.false; + }); + it('listTenants() should resolve with expected number of tenants', () => { const allTenantIds: string[] = []; const tenantOptions2 = deepCopy(tenantOptions); diff --git a/test/unit/auth/tenant-manager.spec.ts b/test/unit/auth/tenant-manager.spec.ts index 9c7ef80be1..52bf955ccd 100644 --- a/test/unit/auth/tenant-manager.spec.ts +++ b/test/unit/auth/tenant-manager.spec.ts @@ -52,6 +52,7 @@ describe('TenantManager', () => { displayName: 'TENANT-DISPLAY-NAME', allowPasswordSignup: true, enableEmailLinkSignin: false, + enableAnonymousUser: true, }; before(() => { @@ -388,6 +389,7 @@ describe('TenantManager', () => { enabled: true, passwordRequired: true, }, + anonymousSignInEnabled: true, }; const expectedTenant = new Tenant(GET_TENANT_RESPONSE); const expectedError = new FirebaseAuthError( @@ -480,6 +482,7 @@ describe('TenantManager', () => { enabled: true, passwordRequired: true, }, + anonymousSignInEnabled: true, }; const expectedTenant = new Tenant(GET_TENANT_RESPONSE); const expectedError = new FirebaseAuthError( diff --git a/test/unit/auth/tenant.spec.ts b/test/unit/auth/tenant.spec.ts index db090b3279..b2ebe6a5d1 100644 --- a/test/unit/auth/tenant.spec.ts +++ b/test/unit/auth/tenant.spec.ts @@ -351,6 +351,7 @@ describe('Tenant', () => { enabled: true, passwordRequired: false, }, + anonymousSignInEnabled: false, multiFactorConfig: deepCopy(clientRequest.multiFactorConfig), testPhoneNumbers: deepCopy(clientRequest.testPhoneNumbers), }); @@ -368,6 +369,7 @@ describe('Tenant', () => { enabled: true, passwordRequired: false, }, + anonymousSignInEnabled: false, }); }); });