@@ -18,6 +18,7 @@ import FirebaseAppCheckInterop
18
18
import FirebaseAuthInterop
19
19
import FirebaseCore
20
20
import FirebaseCoreExtension
21
+ import FirebaseCoreInternal
21
22
#if COCOAPODS
22
23
internal import GoogleUtilities
23
24
#else
@@ -88,21 +89,30 @@ extension Auth: AuthInterop {
88
89
return
89
90
}
90
91
/// Before checking for a standard user, check if we are in a token-only session established
91
- /// by a successful ` exchangeToken` call.
92
- let rGCIPToken = self . rGCIPStateLock . withLock { self . _rGCIPFirebaseToken }
92
+ /// by a successful exchangeToken call.
93
+ let rGCIPToken = self . rGCIPFirebaseTokenLock . withLock { $0 }
93
94
94
95
if let token = rGCIPToken {
95
- /// If a token exists, this session is active. Check for expiration.
96
- if forceRefresh || token. expirationDate < Date ( ) {
97
- let errorMessage = forceRefresh ? " A new token was requested via forceRefresh. " :
98
- " The session token has expired. "
99
- let error = AuthErrorUtils . userTokenExpiredError ( message: errorMessage)
96
+ /// Logic for tokens obtained via exchangeToken (R-GCIP mode)
97
+ if token. expirationDate < Date ( ) {
98
+ /// Token expired
99
+ let error = AuthErrorUtils
100
+ . userTokenExpiredError (
101
+ message: " The firebase access token obtained via exchangeToken() has expired. "
102
+ )
103
+ Auth . wrapMainAsync ( callback: callback, with: . failure( error) )
104
+ } else if forceRefresh {
105
+ /// Token is not expired, but forceRefresh was requested which is currently unsupported
106
+ let error = AuthErrorUtils
107
+ . operationNotAllowedError (
108
+ message: " forceRefresh is not supported for firebase access tokens obtained via exchangeToken(). "
109
+ )
100
110
Auth . wrapMainAsync ( callback: callback, with: . failure( error) )
101
111
} else {
102
- /// The token is valid; return it .
112
+ /// The token is valid and not expired .
103
113
Auth . wrapMainAsync ( callback: callback, with: . success( token. token) )
104
114
}
105
- /// Exit here to prevent falling through to the standard `currentUser` logic .
115
+ /// Exit here as this path is for rGCIPFirebaseToken only .
106
116
return
107
117
}
108
118
/// Fallback to standard `currentUser` logic if not in token-only mode.
@@ -2312,9 +2322,7 @@ public struct FirebaseToken: Sendable {
2312
2322
/// invalidated to prevent a conflicting auth state.
2313
2323
/// Clear any R-GCIP session state when a standard user signs in. This ensures we exit
2314
2324
/// Token-Only Mode.
2315
- self . rGCIPStateLock. withLock {
2316
- self . _rGCIPFirebaseToken = nil
2317
- }
2325
+ self . rGCIPFirebaseTokenLock. withLock { $0 = nil }
2318
2326
/// ... rest of original function
2319
2327
do {
2320
2328
try self . updateCurrentUser ( authResult. user, byForce: false , savingToDisk: true )
@@ -2497,16 +2505,13 @@ public struct FirebaseToken: Sendable {
2497
2505
2498
2506
// MARK: - R-GCIP Token-Only Session State
2499
2507
2500
- /// The session token obtained from a successful `exchangeToken` call.
2508
+ /// The session token obtained from a successful `exchangeToken` call, protected by a lock .
2501
2509
///
2502
2510
/// This property is used to support a "token-only" authentication mode for Regionalized
2503
2511
/// GCIP, where no `User` object is created. It is mutually exclusive with `_currentUser`.
2504
- /// If this property is non-nil, the `AuthInterop` layer will use it for token generation
2512
+ /// If the wrapped value is non-nil, the `AuthInterop` layer will use it for token generation
2505
2513
/// instead of relying on a `currentUser`.
2506
- private var _rGCIPFirebaseToken : FirebaseToken ?
2507
-
2508
- /// A lock to ensure thread-safe access to the R-GCIP token state.
2509
- private let rGCIPStateLock = NSLock ( )
2514
+ private var rGCIPFirebaseTokenLock = FIRAllocatedUnfairLock < FirebaseToken ? > ( initialState: nil )
2510
2515
}
2511
2516
2512
2517
@available ( iOS 13 , * )
@@ -2558,14 +2563,14 @@ public extension Auth {
2558
2563
token: response. firebaseToken,
2559
2564
expirationDate: response. expirationDate
2560
2565
)
2561
- self . rGCIPStateLock . withLock {
2566
+ self . rGCIPFirebaseTokenLock . withLock { token in
2562
2567
// Activating token-only mode requires two steps:
2563
2568
// 1. Ensure no standard user is active, as these states are mutually exclusive.
2564
2569
if self . _currentUser != nil {
2565
2570
try ? self . signOut ( )
2566
2571
}
2567
- // 2. Store the new session token for ` getToken` .
2568
- self . _rGCIPFirebaseToken = firebaseToken
2572
+ // 2. Store the new session token for getToken.
2573
+ token = firebaseToken
2569
2574
}
2570
2575
Auth . wrapMainAsync ( callback: completion, with: . success( firebaseToken) )
2571
2576
} catch {
@@ -2612,11 +2617,11 @@ public extension Auth {
2612
2617
token: response. firebaseToken,
2613
2618
expirationDate: response. expirationDate
2614
2619
)
2615
- rGCIPStateLock . withLock {
2620
+ rGCIPFirebaseTokenLock . withLock { token in
2616
2621
if self . _currentUser != nil {
2617
2622
try ? self . signOut ( )
2618
2623
}
2619
- self . _rGCIPFirebaseToken = firebaseToken
2624
+ token = firebaseToken
2620
2625
}
2621
2626
return firebaseToken
2622
2627
} catch {
0 commit comments