Skip to content

Commit 6232a52

Browse files
authored
Implement onFirebaseTokenChanged method (#9334)
* Implement onFirebaseTokenChanged method
1 parent 45d292b commit 6232a52

File tree

3 files changed

+116
-0
lines changed

3 files changed

+116
-0
lines changed

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

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,28 +553,62 @@ describe('core/auth/auth_impl', () => {
553553
expect(callbackCalled).to.be.false;
554554
});
555555

556+
it('immediately calls firebaseTokenChange if initialization finished', done => {
557+
const token: FirebaseToken = {
558+
token: 'test-token',
559+
expirationTime: 123456
560+
};
561+
(auth as any).firebaseToken = token;
562+
auth._isInitialized = true;
563+
auth.onFirebaseTokenChanged(t => {
564+
expect(t).to.eq(token);
565+
done();
566+
});
567+
});
568+
569+
it('waits for initialization for onFirebaseTokenChanged', done => {
570+
const token: FirebaseToken = {
571+
token: 'test-token',
572+
expirationTime: 123456
573+
};
574+
(auth as any).firebaseToken = token;
575+
auth._isInitialized = false;
576+
auth.onFirebaseTokenChanged(t => {
577+
expect(t).to.eq(token);
578+
done();
579+
});
580+
});
581+
556582
describe('user logs in/out, tokens refresh', () => {
557583
let user: UserInternal;
558584
let authStateCallback: sinon.SinonSpy;
559585
let idTokenCallback: sinon.SinonSpy;
560586
let beforeAuthCallback: sinon.SinonSpy;
587+
let firebaseTokenCallback: sinon.SinonSpy;
588+
const testFirebaseToken: FirebaseToken = {
589+
token: 'test-fb-token',
590+
expirationTime: 123456789
591+
};
561592

562593
beforeEach(() => {
563594
user = testUser(auth, 'uid');
564595
authStateCallback = sinon.spy();
565596
idTokenCallback = sinon.spy();
566597
beforeAuthCallback = sinon.spy();
598+
firebaseTokenCallback = sinon.spy();
567599
});
568600

569601
context('initially currentUser is null', () => {
570602
beforeEach(async () => {
571603
auth.onAuthStateChanged(authStateCallback);
572604
auth.onIdTokenChanged(idTokenCallback);
573605
auth.beforeAuthStateChanged(beforeAuthCallback);
606+
auth.onFirebaseTokenChanged(firebaseTokenCallback);
574607
await auth._updateCurrentUser(null);
575608
authStateCallback.resetHistory();
576609
idTokenCallback.resetHistory();
577610
beforeAuthCallback.resetHistory();
611+
firebaseTokenCallback.resetHistory();
578612
});
579613

580614
it('onAuthStateChange triggers on log in', async () => {
@@ -591,17 +625,26 @@ describe('core/auth/auth_impl', () => {
591625
await auth._updateCurrentUser(user);
592626
expect(beforeAuthCallback).to.have.been.calledWith(user);
593627
});
628+
629+
it('onFirebaseTokenChanged triggers on token set', async () => {
630+
await auth._updateFirebaseToken(testFirebaseToken);
631+
expect(firebaseTokenCallback).to.have.been.calledWith(
632+
testFirebaseToken
633+
);
634+
});
594635
});
595636

596637
context('initially currentUser is user', () => {
597638
beforeEach(async () => {
598639
auth.onAuthStateChanged(authStateCallback);
599640
auth.onIdTokenChanged(idTokenCallback);
600641
auth.beforeAuthStateChanged(beforeAuthCallback);
642+
auth.onFirebaseTokenChanged(firebaseTokenCallback);
601643
await auth._updateCurrentUser(user);
602644
authStateCallback.resetHistory();
603645
idTokenCallback.resetHistory();
604646
beforeAuthCallback.resetHistory();
647+
firebaseTokenCallback.resetHistory();
605648
});
606649

607650
it('onAuthStateChange triggers on log out', async () => {
@@ -638,6 +681,43 @@ describe('core/auth/auth_impl', () => {
638681
});
639682
});
640683

684+
context('initially firebaseToken is null', () => {
685+
beforeEach(async () => {
686+
auth.onFirebaseTokenChanged(firebaseTokenCallback);
687+
await auth._updateFirebaseToken(null);
688+
firebaseTokenCallback.resetHistory();
689+
});
690+
691+
it('onFirebaseTokenChanged triggers on token set', async () => {
692+
await auth._updateFirebaseToken(testFirebaseToken);
693+
expect(firebaseTokenCallback).to.have.been.calledWith(
694+
testFirebaseToken
695+
);
696+
});
697+
});
698+
699+
context('initially firebaseToken is token', () => {
700+
beforeEach(async () => {
701+
auth.onFirebaseTokenChanged(firebaseTokenCallback);
702+
await auth._updateFirebaseToken(testFirebaseToken);
703+
firebaseTokenCallback.resetHistory();
704+
});
705+
706+
it('onFirebaseTokenChanged triggers on token set to null', async () => {
707+
await auth._updateFirebaseToken(null);
708+
expect(firebaseTokenCallback).to.have.been.calledWith(null);
709+
});
710+
711+
it('onFirebaseTokenChanged triggers for token props change', async () => {
712+
const newToken: FirebaseToken = {
713+
...testFirebaseToken,
714+
token: 'new-fb-token'
715+
};
716+
await auth._updateFirebaseToken(newToken);
717+
expect(firebaseTokenCallback).to.have.been.calledWith(newToken);
718+
});
719+
});
720+
641721
context('with Proactive Refresh', () => {
642722
let oldUser: UserInternal;
643723

@@ -739,6 +819,20 @@ describe('core/auth/auth_impl', () => {
739819
expect(cb2).to.have.been.calledWith(user);
740820
});
741821

822+
it('onFirebaseTokenChanged works for multiple listeners', async () => {
823+
const cb1 = sinon.spy();
824+
const cb2 = sinon.spy();
825+
auth.onFirebaseTokenChanged(cb1);
826+
auth.onFirebaseTokenChanged(cb2);
827+
await auth._updateFirebaseToken(null);
828+
cb1.resetHistory();
829+
cb2.resetHistory();
830+
831+
await auth._updateFirebaseToken(testFirebaseToken);
832+
expect(cb1).to.have.been.calledWith(testFirebaseToken);
833+
expect(cb2).to.have.been.calledWith(testFirebaseToken);
834+
});
835+
742836
it('_updateCurrentUser throws if a beforeAuthStateChange callback throws', async () => {
743837
await auth._updateCurrentUser(null);
744838
const cb1 = sinon.stub().throws();

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -672,6 +672,19 @@ export class AuthImpl implements AuthInternal, _FirebaseService {
672672
);
673673
}
674674

675+
onFirebaseTokenChanged(
676+
nextOrObserver: NextOrObserver<FirebaseToken>,
677+
error?: ErrorFn,
678+
completed?: CompleteFn
679+
): Unsubscribe | undefined {
680+
return this.registerStateListener(
681+
this.firebaseTokenSubscription,
682+
nextOrObserver,
683+
error,
684+
completed
685+
);
686+
}
687+
675688
authStateReady(): Promise<void> {
676689
return new Promise((resolve, reject) => {
677690
if (this.currentUser) {

packages/auth/src/model/auth.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,16 @@
1818
import {
1919
Auth,
2020
AuthSettings,
21+
CompleteFn,
2122
Config,
2223
EmulatorConfig,
24+
ErrorFn,
25+
NextOrObserver,
2326
PasswordPolicy,
2427
PasswordValidationStatus,
2528
PopupRedirectResolver,
2629
TenantConfig,
30+
Unsubscribe,
2731
User
2832
} from './public_types';
2933
import { ErrorFactory } from '@firebase/util';
@@ -77,6 +81,11 @@ export interface AuthInternal extends Auth {
7781
currentUser: User | null;
7882
emulatorConfig: EmulatorConfig | null;
7983
getFirebaseAccessToken(forceRefresh?: boolean): Promise<string | null>;
84+
onFirebaseTokenChanged(
85+
nextOrObserver: NextOrObserver<FirebaseToken>,
86+
error?: ErrorFn,
87+
completed?: CompleteFn
88+
): Unsubscribe | undefined;
8089
_agentRecaptchaConfig: RecaptchaConfig | null;
8190
_tenantRecaptchaConfigs: Record<string, RecaptchaConfig>;
8291
_projectPasswordPolicy: PasswordPolicy | null;

0 commit comments

Comments
 (0)