diff --git a/packages/auth/src/core/auth/auth_impl.test.ts b/packages/auth/src/core/auth/auth_impl.test.ts index 3ec648a8c47..2ad345cd546 100644 --- a/packages/auth/src/core/auth/auth_impl.test.ts +++ b/packages/auth/src/core/auth/auth_impl.test.ts @@ -317,6 +317,7 @@ describe('core/auth/auth_impl', () => { let exchangeTokenStub: sinon.SinonStub; let mockToken: FirebaseToken; let expiredMockToken: FirebaseToken; + let soonToExpireMockToken: FirebaseToken; let tokenRefreshHandler: TokenRefreshHandler; const tokenKey = `firebase:persistence-token:${FAKE_APP.options.apiKey!}:${ FAKE_APP.name @@ -331,6 +332,10 @@ describe('core/auth/auth_impl', () => { token: 'test-token', expirationTime: Date.now() + 300000 // 5 minutes from now }; + soonToExpireMockToken = { + token: 'test-token', + expirationTime: Date.now() + 60000 // 1 minutes from now + }; expiredMockToken = { token: 'expired-test-token', expirationTime: Date.now() - 1000 // 1 second ago @@ -364,6 +369,28 @@ describe('core/auth/auth_impl', () => { expect(exchangeTokenStub).not.to.have.been.called; }); + it('should refresh the token if token is expiring in next 1 minute and a token refresh handler is set', async () => { + persistenceStub._get + .withArgs(tokenKey) + .resolves(soonToExpireMockToken as any); + auth.setTokenRefreshHandler(tokenRefreshHandler); + + exchangeTokenStub.callsFake(async () => { + // When exchangeToken is called, simulate that the new token is persisted. + persistenceStub._get.withArgs(tokenKey).resolves(mockToken as any); + }); + + const token = await auth.getFirebaseAccessToken(); + + expect(tokenRefreshHandler.refreshIdpToken).to.have.been.calledOnce; + expect(exchangeTokenStub).to.have.been.calledWith( + auth, + 'test-idp', + 'new-id-token' + ); + expect(token).to.eql('test-token'); + }); + it('should refresh the token if it is expired and a token refresh handler is set', async () => { persistenceStub._get.withArgs(tokenKey).resolves(expiredMockToken as any); auth.setTokenRefreshHandler(tokenRefreshHandler); diff --git a/packages/auth/src/core/auth/auth_impl.ts b/packages/auth/src/core/auth/auth_impl.ts index 76be8bb747a..507bad0ceb5 100644 --- a/packages/auth/src/core/auth/auth_impl.ts +++ b/packages/auth/src/core/auth/auth_impl.ts @@ -115,7 +115,11 @@ export class AuthImpl implements AuthInternal, _FirebaseService { private redirectUser: UserInternal | null = null; private isProactiveRefreshEnabled = false; private readonly EXPECTED_PASSWORD_POLICY_SCHEMA_VERSION: number = 1; - private readonly TOKEN_EXPIRATION_BUFFER = 30_000; + // 1 minute buffer for expiry + // Intended for tokens issued by IdentityPlatform APIs in regionalized Firebase Auth, which can + // have expiry as low as 5 minutes. This should provide enough buffer to the Firebase SDKs for + // token usage before it expires. + private readonly TOKEN_EXPIRATION_BUFFER = 60_000; // Any network calls will set this to true and prevent subsequent emulator // initialization