@@ -140,6 +140,31 @@ extension Auth: AuthInterop {
140140 }
141141}
142142
143+ /// Holds configuration for a R-GCIP tenant.
144+ public struct TenantConfig : Sendable {
145+ public let tenantId : String /// The ID of the tenant.
146+ public let location : String /// The location of the tenant.
147+
148+ /// Initializes a `TenantConfig` instance.
149+ /// - Parameters:
150+ /// - location: The location of the tenant, defaults to "prod-global".
151+ /// - tenantId: The ID of the tenant.
152+ public init ( tenantId: String , location: String = " prod-global " ) {
153+ self . location = location
154+ self . tenantId = tenantId
155+ }
156+ }
157+
158+ /// Holds a Firebase ID token and its expiration.
159+ public struct AuthExchangeToken : Sendable {
160+ public let token : String
161+ public let expirationDate : Date ?
162+ init ( token: String , expirationDate: Date ) {
163+ self . token = token
164+ self . expirationDate = expirationDate
165+ }
166+ }
167+
143168/// Manages authentication for Firebase apps.
144169///
145170/// This class is thread-safe.
@@ -170,16 +195,12 @@ extension Auth: AuthInterop {
170195 /// Gets the `FirebaseApp` object that this auth object is connected to.
171196 @objc public internal( set) weak var app : FirebaseApp ?
172197
173- /// New R-GCIP v2 + BYO-CIAM initializer.
174- ///
175- /// This initializer allows to create an `Auth` instance with a specific `tenantConfig` for
176- /// R-GCIP.
198+ /// Gets the auth object for a `FirebaseApp` with an optional `TenantConfig`.
177199 /// - Parameters:
178- /// - app: The `FirebaseApp` for which to initialize the `Auth` instance.
179- /// - tenantConfig: The configuration for the tenant, including location and tenant ID .
180- /// - Returns: An `Auth` instance configured for the specified tenant.
200+ /// - app: The Firebase app instance.
201+ /// - tenantConfig: The optional configuration for the RGCIP .
202+ /// - Returns: The `Auth` instance associated with the given app and tenant config .
181203 public static func auth( app: FirebaseApp , tenantConfig: TenantConfig ) -> Auth {
182- // start from the legacy initializer so we get a fully-formed Auth object
183204 let auth = auth ( app: app)
184205 kAuthGlobalWorkQueue. sync {
185206 auth. requestConfiguration. location = tenantConfig. location
@@ -188,31 +209,6 @@ extension Auth: AuthInterop {
188209 return auth
189210 }
190211
191- /// Holds configuration for a R-GCIP tenant.
192- public struct TenantConfig : Sendable {
193- public let tenantId : String /// The ID of the tenant.
194- public let location : String /// The location of the tenant.
195-
196- /// Initializes a `TenantConfig` instance.
197- /// - Parameters:
198- /// - location: The location of the tenant, defaults to "prod-global".
199- /// - tenantId: The ID of the tenant.
200- public init ( tenantId: String , location: String = " prod-global " ) {
201- self . location = location
202- self . tenantId = tenantId
203- }
204- }
205-
206- /// Holds a Firebase ID token and its expiration.
207- public struct AuthExchangeToken : Sendable {
208- public let token : String
209- public let expirationDate : Date ?
210- init ( token: String , expirationDate: Date ) {
211- self . token = token
212- self . expirationDate = expirationDate
213- }
214- }
215-
216212 /// Synchronously gets the cached current user, or null if there is none.
217213 @objc public var currentUser : User ? {
218214 kAuthGlobalWorkQueue. sync {
@@ -2471,47 +2467,44 @@ extension Auth: AuthInterop {
24712467
24722468@available ( iOS 13 , * )
24732469public extension Auth {
2474- /// Exchanges a third-party OIDC token for a Firebase STS token using a completion handler .
2470+ /// Exchanges a third-party OIDC token for a Firebase STS token.
24752471 ///
24762472 /// This method is used in R-GCIP (multi-tenant) environments where the `Auth` instance must
24772473 /// be configured with a `TenantConfig`, including `location` and `tenantId`.
2474+ /// Unlike other sign-in methods, this flow *does not* create or update a `User` object.
24782475 ///
24792476 /// - Parameters:
2480- /// - idToken: The OIDC token received from the third-party Identity Provider (IdP).
2481- /// - idpConfigId: The identifier of the OIDC provider configuration defined in Firebase.
2477+ /// - request: The ExchangeTokenRequest containing the OIDC token and other parameters.
24822478 /// - completion: A closure that gets called with either an `AuthTokenResult` or an `Error`.
24832479 func exchangeToken( customToken: String ,
24842480 idpConfigId: String ,
2485- completion: @escaping ( AuthTokenResult ? , Error ? ) -> Void ) {
2481+ completion: @escaping ( AuthExchangeToken ? , Error ? ) -> Void ) {
24862482 // Ensure R-GCIP is configured with location and tenant ID
24872483 guard let _ = requestConfiguration. location,
24882484 let _ = requestConfiguration. tenantId
24892485 else {
2490- completion ( nil , AuthErrorCode . operationNotAllowed)
2486+ Auth . wrapMainAsync (
2487+ callback: completion,
2488+ with: . failure( AuthErrorUtils
2489+ . operationNotAllowedError ( message: " R-GCIP is not configured. " ) )
2490+ )
24912491 return
24922492 }
2493-
2494- // Build the exchange token request
24952493 let request = ExchangeTokenRequest (
24962494 customToken: customToken,
24972495 idpConfigID: idpConfigId,
24982496 config: requestConfiguration
24992497 )
2500-
2501- // Perform the token exchange asynchronously
25022498 Task {
25032499 do {
25042500 let response = try await backend. call ( with: request)
2505- do {
2506- // Try to parse the Firebase token response
2507- do {
2508- let authTokenResult = try AuthTokenResult . tokenResult ( token: response. firebaseToken)
2509- completion ( authTokenResult, nil )
2510- completion ( authTokenResult, nil )
2511- }
2512- } catch {
2513- completion ( nil , AuthErrorCode . malformedJWT)
2514- }
2501+ let authExchangeToken = AuthExchangeToken (
2502+ token: response. firebaseToken,
2503+ expirationDate: response. expirationDate
2504+ )
2505+ Auth . wrapMainAsync ( callback: completion, with: . success( authExchangeToken) )
2506+ } catch {
2507+ Auth . wrapMainAsync ( callback: completion, with: . failure( error) )
25152508 }
25162509 }
25172510 }
@@ -2523,32 +2516,31 @@ public extension Auth {
25232516 ///
25242517 /// The `Auth` instance must be configured with `TenantConfig` containing `location` and
25252518 /// `tenantId`.
2519+ /// Unlike other sign-in methods, this flow *does not* create or update a `User` object.
25262520 ///
25272521 /// - Parameters:
2528- /// - idToken: The OIDC token received from the third-party Identity Provider (IdP).
2529- /// - idpConfigId: The identifier of the OIDC provider configuration defined in Firebase.
2522+ /// - request: The ExchangeTokenRequest containing the OIDC token and other parameters.
25302523 /// - Returns: An `AuthTokenResult` containing the Firebase ID token and its expiration details.
25312524 /// - Throws: An error if R-GCIP is not configured, if the network call fails,
25322525 /// or if the token parsing fails.
2533- func exchangeToken( customToken: String , idpConfigId: String ) async throws -> AuthTokenResult {
2526+ func exchangeToken( customToken: String , idpConfigId: String ) async throws -> AuthExchangeToken {
25342527 // Ensure R-GCIP is configured with location and tenant ID
25352528 guard let _ = requestConfiguration. location,
25362529 let _ = requestConfiguration. tenantId
25372530 else {
2538- throw AuthErrorCode . operationNotAllowed
2531+ throw AuthErrorUtils . operationNotAllowedError ( message : " R-GCIP is not configured. " )
25392532 }
2540-
2541- // Build the exchange token request
25422533 let request = ExchangeTokenRequest (
25432534 customToken: customToken,
25442535 idpConfigID: idpConfigId,
25452536 config: requestConfiguration
25462537 )
2547-
2548- // Perform the backend call and return parsed token
25492538 do {
25502539 let response = try await backend. call ( with: request)
2551- return try AuthTokenResult . tokenResult ( token: response. firebaseToken)
2540+ return AuthExchangeToken (
2541+ token: response. firebaseToken,
2542+ expirationDate: response. expirationDate
2543+ )
25522544 } catch {
25532545 throw error
25542546 }
0 commit comments