@@ -189,25 +189,25 @@ extension Auth: AuthInterop {
189189 }
190190
191191 /// Holds configuration for a R-GCIP tenant.
192- public struct TenantConfig {
193- public let location : String /// The location of the tenant.
192+ public struct TenantConfig : Sendable {
194193 public let tenantId : String /// The ID of the tenant.
194+ public let location : String /// The location of the tenant.
195195
196196 /// Initializes a `TenantConfig` instance.
197197 /// - Parameters:
198198 /// - location: The location of the tenant, defaults to "prod-global".
199199 /// - tenantId: The ID of the tenant.
200- public init ( location: String = " prod-global " , tenantId : String ) {
200+ public init ( tenantId : String , location: String = " prod-global " ) {
201201 self . location = location
202202 self . tenantId = tenantId
203203 }
204204 }
205205
206206 /// Holds a Firebase ID token and its expiration.
207- public struct AuthExchangeToken {
207+ public struct AuthExchangeToken : Sendable {
208208 public let token : String
209209 public let expirationDate : Date ?
210- init ( token: String , expirationDate: Date ? ) {
210+ init ( token: String , expirationDate: Date ) {
211211 self . token = token
212212 self . expirationDate = expirationDate
213213 }
@@ -2471,37 +2471,91 @@ extension Auth: AuthInterop {
24712471
24722472@available ( iOS 13 , * )
24732473public extension Auth {
2474- /// Exchanges a third-party OIDC token for a Firebase STS token.
2474+
2475+ /// Exchanges a third-party OIDC token for a Firebase STS token using a completion handler.
2476+ ///
2477+ /// This method is used in R-GCIP (multi-tenant) environments where the `Auth` instance must
2478+ /// be configured with a `TenantConfig`, including `location` and `tenantId`.
24752479 ///
2476- /// Requires the `Auth` instance to be configured with a `TenantConfig` for R-GCIP.
24772480 /// - Parameters:
2478- /// - idpConfigID: The ID of the OIDC provider configuration.
2479- /// - ciamOidcToken: The OIDC token to exchange.
2480- /// - completion: Called with the Firebase ID token or an error.
2481- @objc func exchangeToken( _ idpConfigID: String ,
2482- _ ciamOidcToken: String ,
2483- completion: @escaping ( String ? , Error ? ) -> Void ) {
2484- // Check if R-GCIP (location and tenantId) is configured.
2485- guard let location = requestConfiguration. location,
2486- let tenantId = requestConfiguration. tenantId
2487- else {
2488- completion ( nil , AuthErrorUtils . operationNotAllowedError (
2489- message: " Set location & tenantId first "
2490- ) )
2491- return
2492- }
2493- let request = ExchangeTokenRequest (
2494- idpConfigID: idpConfigID,
2495- idToken: ciamOidcToken,
2496- config: requestConfiguration
2497- )
2498- Task {
2499- do {
2500- let resp = try await backend. call ( with: request)
2501- DispatchQueue . main. async { completion ( resp. firebaseToken, nil ) }
2502- } catch {
2503- DispatchQueue . main. async { completion ( nil , error) }
2481+ /// - idToken: The OIDC token received from the third-party Identity Provider (IdP).
2482+ /// - idpConfigId: The identifier of the OIDC provider configuration defined in Firebase.
2483+ /// - completion: A closure that gets called with either an `AuthTokenResult` or an `Error`.
2484+ public func exchangeToken(
2485+ idToken: String ,
2486+ idpConfigId: String ,
2487+ completion: @escaping ( AuthTokenResult ? , Error ? ) -> Void
2488+ ) {
2489+ // Ensure R-GCIP is configured with location and tenant ID
2490+ guard let location = requestConfiguration. location,
2491+ let tenantId = requestConfiguration. tenantId
2492+ else {
2493+ completion ( nil , AuthErrorCode . operationNotAllowed)
2494+ return
25042495 }
2505- }
2496+
2497+ // Build the exchange token request
2498+ let request = ExchangeTokenRequest (
2499+ idToken: idToken,
2500+ idpConfigID: idpConfigId,
2501+ config: requestConfiguration
2502+ )
2503+
2504+ // Perform the token exchange asynchronously
2505+ Task {
2506+ do {
2507+ let response = try await backend. call ( with: request)
2508+ do {
2509+ // Try to parse the Firebase token response
2510+ let authTokenResult = try AuthTokenResult . tokenResult ( token: response. firebaseToken)
2511+ DispatchQueue . main. async {
2512+ completion ( authTokenResult, nil )
2513+ }
2514+ } catch {
2515+ // Failed to parse JWT
2516+ DispatchQueue . main. async {
2517+ completion ( nil , AuthErrorCode . malformedJWT)
2518+ }
2519+ }
2520+ } catch {
2521+ // Backend call failed
2522+ DispatchQueue . main. async {
2523+ completion ( nil , error)
2524+ }
2525+ }
2526+ }
2527+ }
2528+
2529+ /// Exchanges a third-party OIDC token for a Firebase STS token using Swift concurrency.
2530+ ///
2531+ /// This async variant performs the same operation as the completion-based method but returns
2532+ /// the result directly and throws on failure.
2533+ ///
2534+ /// The `Auth` instance must be configured with `TenantConfig` containing `location` and `tenantId`.
2535+ ///
2536+ /// - Parameters:
2537+ /// - idToken: The OIDC token received from the third-party Identity Provider (IdP).
2538+ /// - idpConfigId: The identifier of the OIDC provider configuration defined in Firebase.
2539+ /// - Returns: An `AuthTokenResult` containing the Firebase ID token and its expiration details.
2540+ /// - Throws: An error if R-GCIP is not configured, if the network call fails,
2541+ /// or if the token parsing fails.
2542+ public func exchangeToken( idToken: String , idpConfigId: String ) async throws -> AuthTokenResult {
2543+ // Ensure R-GCIP is configured with location and tenant ID
2544+ guard let location = requestConfiguration. location,
2545+ let tenantId = requestConfiguration. tenantId
2546+ else {
2547+ throw AuthErrorCode . operationNotAllowed
2548+ }
2549+
2550+ // Build the exchange token request
2551+ let request = ExchangeTokenRequest (
2552+ idToken: idToken,
2553+ idpConfigID: idpConfigId,
2554+ config: requestConfiguration
2555+ )
2556+
2557+ // Perform the backend call and return parsed token
2558+ let response = try await backend. call ( with: request)
2559+ return try AuthTokenResult . tokenResult ( token: response. firebaseToken)
25062560 }
25072561}
0 commit comments