Skip to content
67 changes: 37 additions & 30 deletions FirebaseAuth/Sources/Swift/Auth/Auth.swift
Original file line number Diff line number Diff line change
Expand Up @@ -123,11 +123,12 @@ extension Auth: AuthInterop {
return
}
// Call back with current user token.
currentUser.internalGetToken(forceRefresh: forceRefresh) { token, error in
DispatchQueue.main.async {
callback(token, error)
currentUser
.internalGetToken(forceRefresh: forceRefresh, backend: strongSelf.backend) { token, error in
DispatchQueue.main.async {
callback(token, error)
}
}
}
}
}

Expand Down Expand Up @@ -292,7 +293,7 @@ extension Auth: AuthInterop {
requestConfiguration: self.requestConfiguration)
Task {
do {
let response = try await AuthBackend.call(with: request)
let response = try await self.backend.call(with: request)
Auth.wrapMainAsync(callback: completion, withParam: response.signinMethods, error: nil)
} catch {
Auth.wrapMainAsync(callback: completion, withParam: nil, error: error)
Expand Down Expand Up @@ -395,7 +396,7 @@ extension Auth: AuthInterop {
let response = try await injectRecaptcha(request: request,
action: AuthRecaptchaAction.signInWithPassword)
#else
let response = try await AuthBackend.call(with: request)
let response = try await backend.call(with: request)
#endif
return try await completeSignIn(
withAccessToken: response.idToken,
Expand Down Expand Up @@ -709,7 +710,7 @@ extension Auth: AuthInterop {
let request = SignUpNewUserRequest(requestConfiguration: self.requestConfiguration)
Task {
do {
let response = try await AuthBackend.call(with: request)
let response = try await self.backend.call(with: request)
let user = try await self.completeSignIn(
withAccessToken: response.idToken,
accessTokenExpirationDate: response.approximateExpirationDate,
Expand Down Expand Up @@ -771,7 +772,7 @@ extension Auth: AuthInterop {
requestConfiguration: self.requestConfiguration)
Task {
do {
let response = try await AuthBackend.call(with: request)
let response = try await self.backend.call(with: request)
let user = try await self.completeSignIn(
withAccessToken: response.idToken,
accessTokenExpirationDate: response.approximateExpirationDate,
Expand Down Expand Up @@ -881,7 +882,7 @@ extension Auth: AuthInterop {
if let inResponse {
response = inResponse
} else {
response = try await AuthBackend.call(with: request)
response = try await self.backend.call(with: request)
}
let user = try await self.completeSignIn(
withAccessToken: response.idToken,
Expand Down Expand Up @@ -993,7 +994,7 @@ extension Auth: AuthInterop {
requestConfiguration: self.requestConfiguration)
Task {
do {
let response = try await AuthBackend.call(with: request)
let response = try await self.backend.call(with: request)

let operation = ActionCodeInfo.actionCodeOperation(forRequestType: response.requestType)
guard let email = response.email else {
Expand Down Expand Up @@ -1433,7 +1434,7 @@ extension Auth: AuthInterop {
/// complete, or fails. Invoked asynchronously on the main thread in the future.
@objc open func revokeToken(withAuthorizationCode authorizationCode: String,
completion: ((Error?) -> Void)? = nil) {
currentUser?.internalGetToken { idToken, error in
currentUser?.internalGetToken(backend: backend) { idToken, error in
if let error {
Auth.wrapMainAsync(completion, error)
return
Expand Down Expand Up @@ -1613,7 +1614,9 @@ extension Auth: AuthInterop {

// MARK: Internal methods

init(app: FirebaseApp, keychainStorageProvider: AuthKeychainStorage = AuthKeychainStorageReal()) {
init(app: FirebaseApp,
keychainStorageProvider: AuthKeychainStorage = AuthKeychainStorageReal(),
backend: AuthBackend = AuthBackend(rpcIssuer: AuthBackendRPCIssuer())) {
Auth.setKeychainServiceNameForApp(app)
self.app = app
mainBundleUrlTypes = Bundle.main
Expand All @@ -1638,6 +1641,7 @@ extension Auth: AuthInterop {
auth: nil,
heartbeatLogger: app.heartbeatLogger,
appCheck: appCheck)
self.backend = backend
super.init()
requestConfiguration.auth = self

Expand Down Expand Up @@ -1911,17 +1915,18 @@ extension Auth: AuthInterop {
return
}
let uid = strongSelf.currentUser?.uid
strongSelf.currentUser?.internalGetToken(forceRefresh: true) { token, error in
if strongSelf.currentUser?.uid != uid {
return
}
if error != nil {
// Kicks off exponential back off logic to retry failed attempt. Starts with one minute
// delay (60 seconds) if this is the first failed attempt.
let rescheduleDelay = retry ? min(delay * 2, 16 * 60) : 60
strongSelf.scheduleAutoTokenRefresh(withDelay: rescheduleDelay, retry: true)
strongSelf.currentUser?
.internalGetToken(forceRefresh: true, backend: strongSelf.backend) { token, error in
if strongSelf.currentUser?.uid != uid {
return
}
if error != nil {
// Kicks off exponential back off logic to retry failed attempt. Starts with one minute
// delay (60 seconds) if this is the first failed attempt.
let rescheduleDelay = retry ? min(delay * 2, 16 * 60) : 60
strongSelf.scheduleAutoTokenRefresh(withDelay: rescheduleDelay, retry: true)
}
}
}
}
}

Expand Down Expand Up @@ -2075,7 +2080,7 @@ extension Auth: AuthInterop {
requestConfiguration: requestConfiguration)
request.autoCreate = !isReauthentication
credential.prepare(request)
let response = try await AuthBackend.call(with: request)
let response = try await backend.call(with: request)
if response.needConfirmation {
let email = response.email
let credential = OAuthCredential(withVerifyAssertionResponse: response)
Expand Down Expand Up @@ -2114,7 +2119,7 @@ extension Auth: AuthInterop {
phoneNumber: phoneNumber,
operation: operation,
requestConfiguration: requestConfiguration)
return try await AuthBackend.call(with: request)
return try await backend.call(with: request)
case let .verification(verificationID, code):
guard verificationID.count > 0 else {
throw AuthErrorUtils.missingVerificationIDError(message: nil)
Expand All @@ -2126,7 +2131,7 @@ extension Auth: AuthInterop {
verificationCode: code,
operation: operation,
requestConfiguration: requestConfiguration)
return try await AuthBackend.call(with: request)
return try await backend.call(with: request)
}
}
#endif
Expand All @@ -2152,7 +2157,7 @@ extension Auth: AuthInterop {
timestamp: credential.timestamp,
displayName: credential.displayName,
requestConfiguration: requestConfiguration)
let response = try await AuthBackend.call(with: request)
let response = try await backend.call(with: request)
let user = try await completeSignIn(withAccessToken: response.idToken,
accessTokenExpirationDate: response
.approximateExpirationDate,
Expand Down Expand Up @@ -2184,7 +2189,7 @@ extension Auth: AuthInterop {
let request = EmailLinkSignInRequest(email: email,
oobCode: actionCode,
requestConfiguration: requestConfiguration)
let response = try await AuthBackend.call(with: request)
let response = try await backend.call(with: request)
let user = try await completeSignIn(withAccessToken: response.idToken,
accessTokenExpirationDate: response
.approximateExpirationDate,
Expand Down Expand Up @@ -2242,7 +2247,7 @@ extension Auth: AuthInterop {
private func wrapAsyncRPCTask(_ request: any AuthRPCRequest, _ callback: ((Error?) -> Void)?) {
Task {
do {
let _ = try await AuthBackend.call(with: request)
let _ = try await self.backend.call(with: request)
Auth.wrapMainAsync(callback, nil)
} catch {
Auth.wrapMainAsync(callback, error)
Expand Down Expand Up @@ -2294,7 +2299,7 @@ extension Auth: AuthInterop {
action: action)
} else {
do {
return try await AuthBackend.call(with: request)
return try await backend.call(with: request)
} catch {
let nsError = error as NSError
if let underlyingError = nsError.userInfo[NSUnderlyingErrorKey] as? NSError,
Expand All @@ -2313,7 +2318,7 @@ extension Auth: AuthInterop {
}
}
}
return try await AuthBackend.call(with: request)
return try await backend.call(with: request)
}
#endif

Expand All @@ -2330,6 +2335,8 @@ extension Auth: AuthInterop {
/// Auth's backend.
var requestConfiguration: AuthRequestConfiguration

let backend: AuthBackend

#if os(iOS)

/// The manager for APNs tokens used by phone number auth.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,7 @@ import Foundation
private func getHeadfulLiteUrl(eventID: String,
sessionID: String) async throws -> URL? {
let authDomain = try await AuthWebUtils
.fetchAuthDomain(withRequestConfiguration: auth.requestConfiguration)
.fetchAuthDomain(withRequestConfiguration: auth.requestConfiguration, backend: auth.backend)
let bundleID = Bundle.main.bundleIdentifier
let clientID = auth.app?.options.clientID
let appID = auth.app?.options.googleAppID
Expand Down
12 changes: 6 additions & 6 deletions FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ import Foundation
.requestConfiguration)

do {
let response = try await AuthBackend.call(with: request)
let response = try await auth.backend.call(with: request)
return response.verificationID
} catch {
return try await handleVerifyErrorWithRetry(error: error,
Expand Down Expand Up @@ -245,7 +245,7 @@ import Foundation
requestConfiguration: auth.requestConfiguration
)

let response = try await AuthBackend.call(with: request)
let response = try await auth.backend.call(with: request)
return response.verificationID
}
guard let session else {
Expand All @@ -263,15 +263,15 @@ import Foundation
let request = StartMFAEnrollmentRequest(idToken: idToken,
enrollmentInfo: startMFARequestInfo,
requestConfiguration: auth.requestConfiguration)
let response = try await AuthBackend.call(with: request)
let response = try await auth.backend.call(with: request)
return response.phoneSessionInfo?.sessionInfo
} else {
let request = StartMFASignInRequest(MFAPendingCredential: session.mfaPendingCredential,
MFAEnrollmentID: session.multiFactorInfo?.uid,
signInInfo: startMFARequestInfo,
requestConfiguration: auth.requestConfiguration)

let response = try await AuthBackend.call(with: request)
let response = try await auth.backend.call(with: request)
return response.responseInfo?.sessionInfo
}
} catch {
Expand Down Expand Up @@ -328,7 +328,7 @@ import Foundation
isSandbox: token.type == AuthAPNSTokenType.sandbox,
requestConfiguration: auth.requestConfiguration)
do {
let verifyResponse = try await AuthBackend.call(with: request)
let verifyResponse = try await auth.backend.call(with: request)
guard let receipt = verifyResponse.receipt,
let timeout = verifyResponse.suggestedTimeOutDate?.timeIntervalSinceNow else {
fatalError("Internal Auth Error: invalid VerifyClientResponse")
Expand Down Expand Up @@ -436,7 +436,7 @@ import Foundation
/// - Parameter eventID: The event ID used for this purpose.
private func reCAPTCHAURL(withEventID eventID: String) async throws -> URL? {
let authDomain = try await AuthWebUtils
.fetchAuthDomain(withRequestConfiguration: auth.requestConfiguration)
.fetchAuthDomain(withRequestConfiguration: auth.requestConfiguration, backend: auth.backend)
let bundleID = Bundle.main.bundleIdentifier
let clientID = auth.app?.options.clientID
let appID = auth.app?.options.googleAppID
Expand Down
16 changes: 1 addition & 15 deletions FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,21 +32,7 @@ class AuthBackend: AuthBackendProtocol {
return "FirebaseAuth.iOS/\(FirebaseVersion()) \(GTMFetcherStandardUserAgentString(nil))"
}

static func call<T: AuthRPCRequest>(with request: T) async throws -> T.Response {
return try await shared.call(with: request)
}

static func setTestRPCIssuer(issuer: AuthBackendRPCIssuer) {
shared.rpcIssuer = issuer
}

static func resetRPCIssuer() {
shared.rpcIssuer = AuthBackendRPCIssuer()
}

private static let shared: AuthBackend = .init(rpcIssuer: AuthBackendRPCIssuer())

private var rpcIssuer: any AuthBackendRPCIssuerProtocol
private let rpcIssuer: any AuthBackendRPCIssuerProtocol

init(rpcIssuer: any AuthBackendRPCIssuerProtocol) {
self.rpcIssuer = rpcIssuer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ private var gAPIHost = "securetoken.googleapis.com"

/// Represents the parameters for the token endpoint.
@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
struct SecureTokenRequest: AuthRPCRequest {
class SecureTokenRequest: AuthRPCRequest {
typealias Response = SecureTokenResponse

/// The type of grant requested.
Expand Down
6 changes: 3 additions & 3 deletions FirebaseAuth/Sources/Swift/MultiFactor/MultiFactor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ import Foundation
.requestConfiguration)
Task {
do {
let response = try await AuthBackend.call(with: request)
let response = try await auth.backend.call(with: request)
do {
let user = try await auth.completeSignIn(withAccessToken: response.idToken,
accessTokenExpirationDate: nil,
Expand Down Expand Up @@ -139,7 +139,7 @@ import Foundation

Task {
do {
let response = try await AuthBackend.call(with: request)
let response = try await auth.backend.call(with: request)
do {
let user = try await auth.completeSignIn(withAccessToken: response.idToken,
accessTokenExpirationDate: nil,
Expand Down Expand Up @@ -217,7 +217,7 @@ import Foundation
requestConfiguration: user.requestConfiguration)
Task {
do {
let response = try await AuthBackend.call(with: request)
let response = try await auth.backend.call(with: request)
do {
let user = try await auth.completeSignIn(withAccessToken: response.idToken,
accessTokenExpirationDate: nil,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ import Foundation
)
Task {
do {
let response = try await AuthBackend.call(with: request)
let response = try await self.auth.backend.call(with: request)
let user = try await self.auth.completeSignIn(withAccessToken: response.idToken,
accessTokenExpirationDate: nil,
refreshToken: response.refreshToken,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@ import Foundation
@objc(generateSecretWithMultiFactorSession:completion:)
open class func generateSecret(with session: MultiFactorSession,
completion: @escaping (TOTPSecret?, Error?) -> Void) {
guard let currentUser = session.currentUser,
let requestConfiguration = currentUser.auth?.requestConfiguration else {
guard let currentUser = session.currentUser, let auth = currentUser.auth else {
let error = AuthErrorUtils.error(code: AuthErrorCode.internalError,
userInfo: [NSLocalizedDescriptionKey:
"Invalid ID token."])
Expand All @@ -42,10 +41,10 @@ import Foundation
let totpEnrollmentInfo = AuthProtoStartMFATOTPEnrollmentRequestInfo()
let request = StartMFAEnrollmentRequest(idToken: session.idToken,
totpEnrollmentInfo: totpEnrollmentInfo,
requestConfiguration: requestConfiguration)
requestConfiguration: auth.requestConfiguration)
Task {
do {
let response = try await AuthBackend.call(with: request)
let response = try await auth.backend.call(with: request)
if let totpSessionInfo = response.totpSessionInfo {
let secret = TOTPSecret(secretKey: totpSessionInfo.sharedSecretKey,
hashingAlgorithm: totpSessionInfo.hashingAlgorithm,
Expand Down
Loading
Loading