@@ -49,7 +49,7 @@ import {
4949 Subscribe
5050} from '@firebase/util' ;
5151
52- import { AuthInternal , ConfigInternal } from '../../model/auth' ;
52+ import { AuthInternal , ConfigInternal , TokenRefreshHandler } from '../../model/auth' ;
5353import { PopupRedirectResolverInternal } from '../../model/popup_redirect' ;
5454import { UserInternal } from '../../model/user' ;
5555import {
@@ -102,6 +102,7 @@ export class AuthImpl implements AuthInternal, _FirebaseService {
102102 currentUser : User | null = null ;
103103 emulatorConfig : EmulatorConfig | null = null ;
104104 firebaseToken : FirebaseToken | null = null ;
105+ tokenRefreshHandler ?: TokenRefreshHandler ;
105106 private operations = Promise . resolve ( ) ;
106107 private persistenceManager ?: PersistenceUserManager ;
107108 private redirectPersistenceManager ?: PersistenceUserManager ;
@@ -112,6 +113,7 @@ export class AuthImpl implements AuthInternal, _FirebaseService {
112113 private redirectUser : UserInternal | null = null ;
113114 private isProactiveRefreshEnabled = false ;
114115 private readonly EXPECTED_PASSWORD_POLICY_SCHEMA_VERSION : number = 1 ;
116+ private readonly TOKEN_EXPIRATION_BUFFER = 30_000 ;
115117
116118 // Any network calls will set this to true and prevent subsequent emulator
117119 // initialization
@@ -159,6 +161,10 @@ export class AuthImpl implements AuthInternal, _FirebaseService {
159161 this . tenantConfig = tenantConfig ;
160162 }
161163
164+ setTokenRefreshHandler ( tokenRefreshHandler : TokenRefreshHandler ) : void {
165+ this . tokenRefreshHandler = tokenRefreshHandler ;
166+ }
167+
162168 _initializeWithPersistence (
163169 persistenceHierarchy : PersistenceInternal [ ] ,
164170 popupRedirectResolver ?: PopupRedirectResolver
@@ -196,7 +202,7 @@ export class AuthImpl implements AuthInternal, _FirebaseService {
196202 }
197203
198204 await this . initializeCurrentUser ( popupRedirectResolver ) ;
199- await this . initializeFirebaseToken ( ) ;
205+ this . firebaseToken = await this . getFirebaseAccessToken ( false ) ;
200206
201207 this . lastNotifiedUid = this . currentUser ?. uid || null ;
202208
@@ -210,6 +216,33 @@ export class AuthImpl implements AuthInternal, _FirebaseService {
210216 return this . _initializationPromise ;
211217 }
212218
219+ async getFirebaseAccessToken ( forceRefresh ?: boolean ) :
220+ Promise < FirebaseToken | null > {
221+ const firebaseAccessToken =
222+ ( await this . persistenceManager ?. getFirebaseToken ( ) ) ?? null ;
223+
224+ if (
225+ firebaseAccessToken &&
226+ this . isFirebaseAccessTokenValid ( firebaseAccessToken ) &&
227+ ! forceRefresh
228+ ) {
229+ this . firebaseToken = firebaseAccessToken ;
230+ this . firebaseTokenSubscription . next ( this . firebaseToken ) ;
231+ return firebaseAccessToken ;
232+ }
233+
234+ if ( firebaseAccessToken && this . tokenRefreshHandler ) {
235+ // Resets the Firebase Access Token to null i.e. logs out the user.
236+ await this . _updateFirebaseToken ( null ) ;
237+ // Awaits for the callback method to execute. The callback method
238+ // is responsible for performing the exchangeToken(auth, valid3pIdpToken)
239+ await this . tokenRefreshHandler . refreshToken ( ) ;
240+ return this . getFirebaseAccessToken ( false ) ;
241+ }
242+
243+ return null ;
244+ }
245+
213246 /**
214247 * If the persistence is changed in another window, the user manager will let us know
215248 */
@@ -240,6 +273,20 @@ export class AuthImpl implements AuthInternal, _FirebaseService {
240273 await this . _updateCurrentUser ( user , /* skipBeforeStateCallbacks */ true ) ;
241274 }
242275
276+ private isFirebaseAccessTokenValid (
277+ firebaseToken : FirebaseToken | null
278+ ) : boolean {
279+ if (
280+ firebaseToken &&
281+ firebaseToken . expirationTime &&
282+ ( Date . now ( ) >
283+ firebaseToken . expirationTime - this . TOKEN_EXPIRATION_BUFFER )
284+ ) {
285+ return false ;
286+ }
287+ return true ;
288+ }
289+
243290 private async initializeCurrentUserFromIdToken (
244291 idToken : string
245292 ) : Promise < void > {
0 commit comments