Skip to content

Commit 2458702

Browse files
committed
Add OIDC token exchange methods for BYO-CIAM
Add OIDC token exchange methods for BYO-CIAM#
1 parent aebb8bb commit 2458702

File tree

1 file changed

+111
-0
lines changed

1 file changed

+111
-0
lines changed

FirebaseAuth/Sources/Swift/Auth/Auth.swift

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2463,4 +2463,115 @@ public extension Auth {
24632463
self.tenantId = tenantId
24642464
}
24652465
}
2466+
2467+
/// Represents the result of a successful OIDC token exchange, containing a Firebase ID token
2468+
/// and its expiration.
2469+
struct FirebaseToken: Sendable {
2470+
/// The Firebase ID token string.
2471+
public let token: String
2472+
/// The date at which the Firebase ID token expires.
2473+
public let expirationDate: Date
2474+
2475+
init(token: String, expirationDate: Date) {
2476+
self.token = token
2477+
self.expirationDate = expirationDate
2478+
}
2479+
}
2480+
2481+
/// Exchanges a third-party OIDC token for a Firebase ID token.
2482+
///
2483+
/// This method is used for Bring Your Own CIAM (BYO-CIAM) in Regionalized GCIP (R-GCIP),
2484+
/// where the `Auth` instance must be configured with a `TenantConfig`, including `location`
2485+
/// and `tenantId`, typically by using `Auth.auth(app:tenantConfig:)`.
2486+
///
2487+
/// Unlike standard sign-in methods, this flow *does not* create or update a `User` object and
2488+
/// *does not* set `CurrentUser` on the `Auth` instance. It only returns a Firebase token.
2489+
///
2490+
/// - Parameters:
2491+
/// - oidcToken: The OIDC ID token obtained from the third-party identity provider.
2492+
/// - idpConfigId: The ID of the Identity Provider configuration within your GCIP tenant
2493+
/// (e.g., "oidc.my-provider").
2494+
/// - useStaging: A Boolean value indicating whether to use the staging Identity Platform
2495+
/// backend. Defaults to `false`.
2496+
/// - completion: A closure that is called asynchronously on the main thread with either a
2497+
/// `FirebaseToken` on success or an `Error` on failure.
2498+
func exchangeToken(idToken: String,
2499+
idpConfigId: String,
2500+
useStaging: Bool = false,
2501+
completion: @escaping (FirebaseToken?, Error?) -> Void) {
2502+
/// Ensure R-GCIP is configured with location and tenant ID
2503+
guard let _ = requestConfiguration.tenantConfig?.location,
2504+
let _ = requestConfiguration.tenantConfig?.tenantId
2505+
else {
2506+
Auth.wrapMainAsync(
2507+
callback: completion,
2508+
with: .failure(AuthErrorUtils
2509+
.operationNotAllowedError(
2510+
message: "Auth instance must be configured with a TenantConfig, including location and tenantId, to use exchangeToken."
2511+
))
2512+
)
2513+
return
2514+
}
2515+
let request = ExchangeTokenRequest(
2516+
idToken: idToken,
2517+
idpConfigID: idpConfigId,
2518+
config: requestConfiguration,
2519+
useStaging: true
2520+
)
2521+
Task {
2522+
do {
2523+
let response = try await backend.call(with: request)
2524+
let firebaseToken = FirebaseToken(
2525+
token: response.firebaseToken,
2526+
expirationDate: response.expirationDate
2527+
)
2528+
Auth.wrapMainAsync(callback: completion, with: .success(firebaseToken))
2529+
} catch {
2530+
Auth.wrapMainAsync(callback: completion, with: .failure(error))
2531+
}
2532+
}
2533+
}
2534+
2535+
/// Exchanges a third-party OIDC ID token for a Firebase ID token using Swift concurrency.
2536+
///
2537+
/// This method is used for Bring Your Own CIAM (BYO-CIAM) in Regionalized GCIP (R-GCIP),
2538+
/// where the `Auth` instance must be configured with a `TenantConfig`, including `location`
2539+
/// and `tenantId`, typically by using `Auth.auth(app:tenantConfig:)`.
2540+
///
2541+
/// Unlike standard sign-in methods, this flow *does not* create or update a `User`object and
2542+
/// *does not* set `CurrentUser` on the `Auth` instance. It only returns a Firebase token.
2543+
///
2544+
/// - Parameters:
2545+
/// - oidcToken: The OIDC ID token obtained from the third-party identity provider.
2546+
/// - idpConfigId: The ID of the Identity Provider configuration within your GCIP tenant
2547+
/// (e.g., "oidc.my-provider").
2548+
/// - useStaging: A Boolean value indicating whether to use the staging Identity Platform
2549+
/// backend. Defaults to `false`.
2550+
/// - Returns: A `FirebaseToken` containing the Firebase ID token and its expiration date.
2551+
/// - Throws: An error if the `Auth` instance is not configured for R-GCIP, if the network
2552+
/// call fails, or if the token response parsing fails.
2553+
func exchangeToken(idToken: String, idpConfigId: String,
2554+
useStaging: Bool = false) async throws -> FirebaseToken {
2555+
// Ensure R-GCIP is configured with location and tenant ID
2556+
guard let _ = requestConfiguration.tenantConfig?.location,
2557+
let _ = requestConfiguration.tenantConfig?.tenantId
2558+
else {
2559+
throw AuthErrorUtils.operationNotAllowedError(message: "R-GCIP is not configured.")
2560+
}
2561+
let request = ExchangeTokenRequest(
2562+
idToken: idToken,
2563+
idpConfigID: idpConfigId,
2564+
config: requestConfiguration,
2565+
useStaging: true
2566+
)
2567+
do {
2568+
let response = try await backend.call(with: request)
2569+
return FirebaseToken(
2570+
token: response.firebaseToken,
2571+
expirationDate: response.expirationDate
2572+
)
2573+
} catch {
2574+
throw error
2575+
}
2576+
}
24662577
}

0 commit comments

Comments
 (0)