Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 19 additions & 11 deletions FirebaseAuth/Sources/Swift/Auth/Auth.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1320,10 +1320,17 @@ extension Auth: AuthInterop {
/// dictionary will contain more information about the error encountered.
@objc(signOut:) open func signOut() throws {
try kAuthGlobalWorkQueue.sync {
guard self._currentUser != nil else {
return
if self._currentUser != nil {
// Clear standard user session if one exists.
try self.updateCurrentUser(nil, byForce: false, savingToDisk: true)
}

// Clear R-GCIP token-only session.
self.rGCIPFirebaseTokenLock.withLock { token in
if token != nil {
token = nil
}
}
return try self.updateCurrentUser(nil, byForce: false, savingToDisk: true)
}
}

Expand Down Expand Up @@ -2541,13 +2548,17 @@ public extension Auth {
/// call fails, or if the token response parsing fails.
func exchangeToken(idToken: String, idpConfigId: String,
useStaging: Bool = false) async throws -> FirebaseToken {
// Ensure R-GCIP is configured with location and tenant ID
guard let _ = requestConfiguration.tenantConfig?.location,
let _ = requestConfiguration.tenantConfig?.tenantId
else {
/// Ensure R-GCIP is configured with location and tenant ID.
guard requestConfiguration.tenantConfig != nil else {
/// This should never happen in production code, as it indicates a misconfiguration.
fatalError("R-GCIP is not configured correctly.")
}
/// This method should only be called on an R-GCIP instance
guard _currentUser == nil else {
fatalError(
"exchangeToken cannot be called on an Auth instance with an active standard user session."
)
}
let request = ExchangeTokenRequest(
idToken: idToken,
idpConfigID: idpConfigId,
Expand All @@ -2560,11 +2571,8 @@ public extension Auth {
token: response.firebaseToken,
expirationDate: response.expirationDate
)
// Lock and update the token, signing out any current user.
// Lock and update the R-GCIP token.
rGCIPFirebaseTokenLock.withLock { token in
if self._currentUser != nil {
try? self.signOut()
}
token = newToken
}
return newToken
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,25 +25,37 @@ class AppManager {
private var otherApp: FirebaseApp
var app: FirebaseApp

// Initialise Auth with TenantConfig
let tenantConfig = TenantConfig(tenantId: "Foo-e2e-tenant-007", location: "global")
// TenantConfig for regionalized Auth
private let tenantConfig = TenantConfig(tenantId: "Foo-e2e-tenant-007", location: "global")

// Cached Auth instances
private var defaultAppAuth: Auth
private var otherAppAuth: Auth
private var regionalAuthInstance: Auth

func auth() -> Auth {
return Auth.auth(app: app, tenantConfig: tenantConfig)
/// Always return the specific regional instance
return regionalAuthInstance
}

private init() {
defaultApp = FirebaseApp.app()!
app = FirebaseApp.app()!
defaultAppAuth = Auth.auth(app: defaultApp)
guard let path = Bundle.main.path(forResource: "GoogleService-Info_multi", ofType: "plist"),
let options = FirebaseOptions(contentsOfFile: path) else {
fatalError("GoogleService-Info_multi.plist must be added to the project")
}

FirebaseApp.configure(name: "OtherApp", options: options)
if FirebaseApp.app(name: "OtherApp") == nil {
FirebaseApp.configure(name: "OtherApp", options: options)
}
guard let other = FirebaseApp.app(name: "OtherApp") else {
fatalError("Failed to find OtherApp")
}
otherApp = other
otherAppAuth = Auth.auth(app: otherApp)
regionalAuthInstance = Auth.auth(app: otherApp, tenantConfig: tenantConfig)
print("AppManager init: regionalAuthInstance created: \(regionalAuthInstance)")
app = defaultApp
}

func toggle() {
Expand All @@ -53,4 +65,13 @@ class AppManager {
app = defaultApp
}
}

/// Function to get the standard Auth instance based on the current 'app'
func standardAuth() -> Auth {
if app == defaultApp {
return defaultAppAuth
} else {
return otherAppAuth
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ enum AuthMenu: String {
case totpEnroll
case multifactorUnenroll
case exchangeToken
case exchangeTokenSignOut

// More intuitively named getter for `rawValue`.
var id: String { rawValue }
Expand Down Expand Up @@ -143,6 +144,8 @@ enum AuthMenu: String {
// R-GCIP Exchange Token
case .exchangeToken:
return "Exchange Token"
case .exchangeTokenSignOut:
return "Sign Out from R-GCIP"
}
}

Expand Down Expand Up @@ -226,6 +229,8 @@ enum AuthMenu: String {
self = .multifactorUnenroll
case "Exchange Token":
self = .exchangeToken
case "Sign Out from R-GCIP":
self = .exchangeTokenSignOut
default:
return nil
}
Expand Down Expand Up @@ -364,6 +369,7 @@ class AuthMenuData: DataSourceProvidable {
let header = "Exchange Token [Regionalized Auth]"
let items: [Item] = [
Item(title: AuthMenu.exchangeToken.name),
Item(title: AuthMenu.exchangeTokenSignOut.name),
]
return Section(headerDescription: header, items: items)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,9 @@ class AuthViewController: UIViewController, DataSourceProviderDelegate {

case .exchangeToken:
callExchangeToken()

case .exchangeTokenSignOut:
callExchangeTokenSignOut()
}
}

Expand Down Expand Up @@ -1172,6 +1175,35 @@ extension AuthViewController: ASAuthorizationControllerDelegate,
}
}

private func callExchangeTokenSignOut() {
Task {
do {
try AppManager.shared.auth().signOut()
print("Sign out successful.")
await MainActor.run {
let alert = UIAlertController(
title: "Signed Out",
message: "The current R-GCIP session has been signed out.",
preferredStyle: .alert
)
alert.addAction(UIAlertAction(title: "OK", style: .default))
self.present(alert, animated: true)
}
} catch {
print("Failed to sign out: \(error)")
await MainActor.run {
let alert = UIAlertController(
title: "Sign Out Error",
message: error.localizedDescription,
preferredStyle: .alert
)
alert.addAction(UIAlertAction(title: "OK", style: .default))
self.present(alert, animated: true)
}
}
}
}

// Helper function to truncate strings
private func truncateString(_ string: String, maxLength: Int) -> String {
if string.count > maxLength {
Expand Down
Loading