Skip to content

Commit e199ba1

Browse files
authored
Merge 97752d5 into 15b2302
2 parents 15b2302 + 97752d5 commit e199ba1

File tree

5 files changed

+101
-1
lines changed

5 files changed

+101
-1
lines changed

common/api-review/auth.api.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ export interface Auth {
9292
languageCode: string | null;
9393
readonly name: string;
9494
onAuthStateChanged(nextOrObserver: NextOrObserver<User | null>, error?: ErrorFn, completed?: CompleteFn): Unsubscribe;
95+
// (undocumented)
96+
onFirebaseTokenChanged(nextOrObserver: NextOrObserver<FirebaseToken | null>, error?: ErrorFn, completed?: CompleteFn): Unsubscribe;
9597
onIdTokenChanged(nextOrObserver: NextOrObserver<User | null>, error?: ErrorFn, completed?: CompleteFn): Unsubscribe;
9698
setPersistence(persistence: Persistence): Promise<void>;
9799
readonly settings: AuthSettings;

docs-devsite/auth.auth.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ export interface Auth
4242
| [authStateReady()](./auth.auth.md#authauthstateready) | returns a promise that resolves immediately when the initial auth state is settled. When the promise resolves, the current user might be a valid user or <code>null</code> if the user signed out. |
4343
| [beforeAuthStateChanged(callback, onAbort)](./auth.auth.md#authbeforeauthstatechanged) | Adds a blocking callback that runs before an auth state change sets a new user. |
4444
| [onAuthStateChanged(nextOrObserver, error, completed)](./auth.auth.md#authonauthstatechanged) | Adds an observer for changes to the user's sign-in state. |
45+
| [onFirebaseTokenChanged(nextOrObserver, error, completed)](./auth.auth.md#authonfirebasetokenchanged) | |
4546
| [onIdTokenChanged(nextOrObserver, error, completed)](./auth.auth.md#authonidtokenchanged) | Adds an observer for changes to the signed-in user's ID token. |
4647
| [setPersistence(persistence)](./auth.auth.md#authsetpersistence) | Changes the type of persistence on the <code>Auth</code> instance. |
4748
| [signOut()](./auth.auth.md#authsignout) | Signs out the current user. This does not automatically revoke the user's ID token. |
@@ -227,6 +228,26 @@ onAuthStateChanged(nextOrObserver: NextOrObserver<User | null>, error?: ErrorFn,
227228

228229
[Unsubscribe](./util.md#unsubscribe)
229230

231+
## Auth.onFirebaseTokenChanged()
232+
233+
<b>Signature:</b>
234+
235+
```typescript
236+
onFirebaseTokenChanged(nextOrObserver: NextOrObserver<FirebaseToken | null>, error?: ErrorFn, completed?: CompleteFn): Unsubscribe;
237+
```
238+
239+
#### Parameters
240+
241+
| Parameter | Type | Description |
242+
| --- | --- | --- |
243+
| nextOrObserver | [NextOrObserver](./auth.md#nextorobserver)<!-- -->&lt;[FirebaseToken](./auth.firebasetoken.md#firebasetoken_interface) \| null&gt; | |
244+
| error | [ErrorFn](./util.md#errorfn) | |
245+
| completed | [CompleteFn](./util.md#completefn) | |
246+
247+
<b>Returns:</b>
248+
249+
[Unsubscribe](./util.md#unsubscribe)
250+
230251
## Auth.onIdTokenChanged()
231252

232253
Adds an observer for changes to the signed-in user's ID token.

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

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ export class AuthImpl implements AuthInternal, _FirebaseService {
107107
private redirectPersistenceManager?: PersistenceUserManager;
108108
private authStateSubscription = new Subscription<User>(this);
109109
private idTokenSubscription = new Subscription<User>(this);
110+
private firebaseTokenSubscription = new Subscription<FirebaseToken>(this);
110111
private readonly beforeStateQueue = new AuthMiddlewareQueue(this);
111112
private redirectUser: UserInternal | null = null;
112113
private isProactiveRefreshEnabled = false;
@@ -195,6 +196,7 @@ export class AuthImpl implements AuthInternal, _FirebaseService {
195196
}
196197

197198
await this.initializeCurrentUser(popupRedirectResolver);
199+
await this.initializeFirebaseToken();
198200

199201
this.lastNotifiedUid = this.currentUser?.uid || null;
200202

@@ -403,6 +405,12 @@ export class AuthImpl implements AuthInternal, _FirebaseService {
403405
return this.directlySetCurrentUser(user);
404406
}
405407

408+
private async initializeFirebaseToken(): Promise<void> {
409+
this.firebaseToken =
410+
(await this.persistenceManager?.getFirebaseToken()) ?? null;
411+
this.firebaseTokenSubscription.next(this.firebaseToken);
412+
}
413+
406414
useDeviceLanguage(): void {
407415
this.languageCode = _getUserLanguage();
408416
}
@@ -461,6 +469,12 @@ export class AuthImpl implements AuthInternal, _FirebaseService {
461469
firebaseToken: FirebaseToken | null
462470
): Promise<void> {
463471
this.firebaseToken = firebaseToken;
472+
this.firebaseTokenSubscription.next(firebaseToken);
473+
if (firebaseToken) {
474+
await this.assertedPersistence.setFirebaseToken(firebaseToken);
475+
} else {
476+
await this.assertedPersistence.removeFirebaseToken();
477+
}
464478
}
465479

466480
async signOut(): Promise<void> {
@@ -577,6 +591,29 @@ export class AuthImpl implements AuthInternal, _FirebaseService {
577591
);
578592
}
579593

594+
onFirebaseTokenChanged(
595+
nextOrObserver: NextOrObserver<FirebaseToken | null>,
596+
error?: ErrorFn,
597+
completed?: CompleteFn
598+
): Unsubscribe {
599+
if (typeof nextOrObserver === 'function') {
600+
const unsubscribe = this.firebaseTokenSubscription.addObserver(
601+
nextOrObserver,
602+
error,
603+
completed
604+
);
605+
return () => {
606+
unsubscribe();
607+
};
608+
} else {
609+
const unsubscribe =
610+
this.firebaseTokenSubscription.addObserver(nextOrObserver);
611+
return () => {
612+
unsubscribe();
613+
};
614+
}
615+
}
616+
580617
beforeAuthStateChanged(
581618
callback: (user: User | null) => void | Promise<void>,
582619
onAbort?: () => void

packages/auth/src/core/persistence/persistence_user_manager.ts

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import { getAccountInfo } from '../../api/account_management/account';
1919
import { ApiKey, AppName, AuthInternal } from '../../model/auth';
20+
import { FirebaseToken } from '../../model/public_types';
2021
import { UserInternal } from '../../model/user';
2122
import { PersistedBlob, PersistenceInternal } from '../persistence';
2223
import { UserImpl } from '../user/user_impl';
@@ -27,7 +28,8 @@ export const enum KeyName {
2728
AUTH_USER = 'authUser',
2829
AUTH_EVENT = 'authEvent',
2930
REDIRECT_USER = 'redirectUser',
30-
PERSISTENCE_USER = 'persistence'
31+
PERSISTENCE_USER = 'persistence',
32+
PERSISTENCE_TOKEN = 'persistence-token'
3133
}
3234
export const enum Namespace {
3335
PERSISTENCE = 'firebase'
@@ -44,6 +46,7 @@ export function _persistenceKeyName(
4446
export class PersistenceUserManager {
4547
private readonly fullUserKey: string;
4648
private readonly fullPersistenceKey: string;
49+
private readonly firebaseTokenPersistenceKey: string;
4750
private readonly boundEventHandler: () => void;
4851

4952
private constructor(
@@ -58,6 +61,11 @@ export class PersistenceUserManager {
5861
config.apiKey,
5962
name
6063
);
64+
this.firebaseTokenPersistenceKey = _persistenceKeyName(
65+
KeyName.PERSISTENCE_TOKEN,
66+
config.apiKey,
67+
name
68+
);
6169
this.boundEventHandler = auth._onStorageEvent.bind(auth);
6270
this.persistence._addListener(this.fullUserKey, this.boundEventHandler);
6371
}
@@ -66,6 +74,32 @@ export class PersistenceUserManager {
6674
return this.persistence._set(this.fullUserKey, user.toJSON());
6775
}
6876

77+
setFirebaseToken(firebaseToken: FirebaseToken): Promise<void> {
78+
return this.persistence._set(this.firebaseTokenPersistenceKey, {
79+
token: firebaseToken.token,
80+
expirationTime: firebaseToken.expirationTime
81+
});
82+
}
83+
84+
async getFirebaseToken(): Promise<FirebaseToken | null> {
85+
const blob = await this.persistence._get<PersistedBlob>(
86+
this.firebaseTokenPersistenceKey
87+
);
88+
if (!blob) {
89+
return null;
90+
}
91+
const token = blob.token as string;
92+
const expirationTime = blob.expirationTime as number;
93+
return {
94+
token,
95+
expirationTime
96+
};
97+
}
98+
99+
removeFirebaseToken(): Promise<void> {
100+
return this.persistence._remove(this.firebaseTokenPersistenceKey);
101+
}
102+
69103
async getCurrentUser(): Promise<UserInternal | null> {
70104
const blob = await this.persistence._get<PersistedBlob | string>(
71105
this.fullUserKey

packages/auth/src/model/public_types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,12 @@ export interface Auth {
280280
callback: (user: User | null) => void | Promise<void>,
281281
onAbort?: () => void
282282
): Unsubscribe;
283+
284+
onFirebaseTokenChanged(
285+
nextOrObserver: NextOrObserver<FirebaseToken | null>,
286+
error?: ErrorFn,
287+
completed?: CompleteFn
288+
): Unsubscribe;
283289
/**
284290
* Adds an observer for changes to the signed-in user's ID token.
285291
*

0 commit comments

Comments
 (0)