Skip to content

Commit ab59dd2

Browse files
authored
Implement addAuthTokenListener for Regional Auth (#9324)
* Add IdTokenListener for Firebase Token * Adding Unit test for Firebase Auth Token Listener * Removing onFirebaseTokenChanged from public_types * Updating the chrome_validated_version for tests * Updating the chrome_validated_version for tests * Updating the chrome_validated_version for tests * Updating the chrome_validated_version for tests * Updating the chrome_validated_version for tests * Add type in unit test * Commenting new tests * Updating method signature * Update sinon version * Update yarn.lock * Remove unwanted changes * Remove unwanted changes * chore: Restore yarn.lock * Restore yarn.lock * Remove yarn.lock * Fix syntax errors * Add todo for Regional Auth proactive refresh
1 parent 6232a52 commit ab59dd2

File tree

4 files changed

+89
-7
lines changed

4 files changed

+89
-7
lines changed

packages/auth/src/core/auth/auth_impl.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -676,7 +676,7 @@ export class AuthImpl implements AuthInternal, _FirebaseService {
676676
nextOrObserver: NextOrObserver<FirebaseToken>,
677677
error?: ErrorFn,
678678
completed?: CompleteFn
679-
): Unsubscribe | undefined {
679+
): Unsubscribe {
680680
return this.registerStateListener(
681681
this.firebaseTokenSubscription,
682682
nextOrObserver,

packages/auth/src/core/auth/firebase_internal.test.ts

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,72 @@ describe('core/auth/firebase_internal - Regional Firebase Auth', () => {
327327
});
328328
});
329329

330+
context('addAuthTokenListener', () => {
331+
let isProactiveRefresh = false;
332+
const initialToken = 'initial-regional-token';
333+
const updatedToken = 'updated-regional-token';
334+
beforeEach(async () => {
335+
isProactiveRefresh = false;
336+
337+
sinon
338+
.stub(regionalAuth as any, '_startProactiveRefresh')
339+
.callsFake(() => {
340+
isProactiveRefresh = true;
341+
});
342+
sinon.stub(regionalAuth as any, '_stopProactiveRefresh').callsFake(() => {
343+
isProactiveRefresh = false;
344+
});
345+
await regionalAuth._updateFirebaseToken({
346+
token: initialToken,
347+
expirationTime: now + 300_000
348+
});
349+
});
350+
351+
it('gets called with the current token (or null)', done => {
352+
let firstCall = true;
353+
354+
regionalAuthInternal.addAuthTokenListener(token => {
355+
if (firstCall) {
356+
firstCall = false;
357+
expect(token).to.eq(initialToken);
358+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
359+
regionalAuth._updateFirebaseToken({
360+
token: updatedToken,
361+
expirationTime: now + 300_000
362+
});
363+
return;
364+
}
365+
366+
expect(token).to.eq(updatedToken);
367+
expect(isProactiveRefresh).to.be.true;
368+
done();
369+
});
370+
});
371+
372+
it('gets called on subsequent updates', async () => {
373+
let regionalCount = 0;
374+
regionalAuthInternal.addAuthTokenListener(() => {
375+
regionalCount++;
376+
});
377+
378+
await regionalAuth.getFirebaseAccessToken();
379+
await regionalAuth.getFirebaseAccessToken();
380+
await regionalAuth.getFirebaseAccessToken();
381+
await regionalAuth.getFirebaseAccessToken();
382+
383+
expect(regionalCount).to.eq(5);
384+
});
385+
386+
it('errors if Regional Auth is not initialized', () => {
387+
delete (regionalAuth as unknown as Record<string, unknown>)[
388+
'_initializationPromise'
389+
];
390+
expect(() =>
391+
regionalAuthInternal.addAuthTokenListener(() => {})
392+
).to.throw(FirebaseError, 'auth/dependent-sdk-initialized-before-auth');
393+
});
394+
});
395+
330396
context('getUid', () => {
331397
it('throws an error if regionalAuth is initialized', () => {
332398
expect(() => regionalAuthInternal.getUid()).to.throw(

packages/auth/src/core/auth/firebase_internal.ts

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
import { Unsubscribe } from '@firebase/util';
1919
import { FirebaseAuthInternal } from '@firebase/auth-interop-types';
2020

21-
import { AuthInternal } from '../../model/auth';
21+
import { AuthInternal, FirebaseToken } from '../../model/auth';
2222
import { UserInternal } from '../../model/user';
2323
import { _assert } from '../util/assert';
2424
import { AuthErrorCode } from '../errors';
@@ -64,12 +64,28 @@ export class AuthInterop implements FirebaseAuthInternal {
6464
return;
6565
}
6666

67-
const unsubscribe = this.auth.onIdTokenChanged(user => {
68-
listener(
69-
(user as UserInternal | null)?.stsTokenManager.accessToken || null
67+
let unsubscribe: Unsubscribe;
68+
if (this.auth.tenantConfig) {
69+
unsubscribe = this.auth.onFirebaseTokenChanged(
70+
(firebaseToken: FirebaseToken | null) => {
71+
try {
72+
listener(firebaseToken?.token || null);
73+
} catch (error) {
74+
console.error('Failed to retrieve firebase token:', error);
75+
listener(null);
76+
}
77+
}
7078
);
71-
});
79+
} else {
80+
unsubscribe = this.auth.onIdTokenChanged(user => {
81+
listener(
82+
(user as UserInternal | null)?.stsTokenManager.accessToken || null
83+
);
84+
});
85+
}
86+
7287
this.internalListeners.set(listener, unsubscribe);
88+
// TODO - b/455792813: Handle proactive refresh for R-GCIP Firebase Token.
7389
this.updateProactiveRefresh();
7490
}
7591

packages/auth/src/model/auth.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ export interface AuthInternal extends Auth {
8585
nextOrObserver: NextOrObserver<FirebaseToken>,
8686
error?: ErrorFn,
8787
completed?: CompleteFn
88-
): Unsubscribe | undefined;
88+
): Unsubscribe;
8989
_agentRecaptchaConfig: RecaptchaConfig | null;
9090
_tenantRecaptchaConfigs: Record<string, RecaptchaConfig>;
9191
_projectPasswordPolicy: PasswordPolicy | null;

0 commit comments

Comments
 (0)