diff --git a/FirebaseAuth/CHANGELOG.md b/FirebaseAuth/CHANGELOG.md index 310cbd2c7ad..4889fe65ba3 100644 --- a/FirebaseAuth/CHANGELOG.md +++ b/FirebaseAuth/CHANGELOG.md @@ -1,5 +1,6 @@ # Unreleased - [fixed] Add a mechanism to prevent concurrent token refreshes. (#15474) +- [fixed] Fix password reset process for Signin With Apple. (#6091) - [fixed] Fix "weak never mutated" build warning introduced in Xcode 26.2. # 12.2.0 diff --git a/FirebaseAuth/Sources/Swift/Auth/Auth.swift b/FirebaseAuth/Sources/Swift/Auth/Auth.swift index e75a551fb9b..23fe8e9ca4c 100644 --- a/FirebaseAuth/Sources/Swift/Auth/Auth.swift +++ b/FirebaseAuth/Sources/Swift/Auth/Auth.swift @@ -1168,9 +1168,14 @@ extension Auth: AuthInterop { actionCodeSettings: ActionCodeSettings?, completion: ((Error?) -> Void)? = nil) { kAuthGlobalWorkQueue.async { + let finalActionCodeSettings = actionCodeSettings ?? ActionCodeSettings() + if let customAuthDomain = self.customAuthDomain, + finalActionCodeSettings.linkDomain == nil { + finalActionCodeSettings.linkDomain = customAuthDomain + } let request = GetOOBConfirmationCodeRequest.passwordResetRequest( email: email, - actionCodeSettings: actionCodeSettings, + actionCodeSettings: finalActionCodeSettings, requestConfiguration: self.requestConfiguration ) #if os(iOS) diff --git a/FirebaseAuth/Tests/Unit/AuthTests.swift b/FirebaseAuth/Tests/Unit/AuthTests.swift index 5ae1d522108..72eaa6d8c1b 100644 --- a/FirebaseAuth/Tests/Unit/AuthTests.swift +++ b/FirebaseAuth/Tests/Unit/AuthTests.swift @@ -1591,7 +1591,82 @@ class AuthTests: RPCBaseTests { @brief Tests the flow of a successful @c sendPasswordReset call. */ func testSendPasswordResetEmailSuccess() throws { - let expectation = self.expectation(description: #function) + try checkSendPasswordResetWithLinkDomain( + customAuthDomain: nil, + actionCodeSettings: nil, + expectedLinkDomain: nil, + description: #function + ) + } + + /** @fn testSendPasswordResetEmailWithActionCodeSettingsLinkDomainSet + @brief Tests the flow of a successful @c sendPasswordReset call with actionCodeSettings and + linkDomain set. + */ + func testSendPasswordResetEmailWithActionCodeSettingsLinkDomainSet() throws { + let kCustomAuthDomain = "test.page.link" + let kActionCodeSettingsLinkDomain = "actioncode.page.link" + auth.customAuthDomain = kCustomAuthDomain + + let actionCodeSettings = ActionCodeSettings() + actionCodeSettings.linkDomain = kActionCodeSettingsLinkDomain + actionCodeSettings.url = + URL( + string: "https://\(kActionCodeSettingsLinkDomain)/_next/verify?mode=resetPassword&oobCode=oobCode" + )! + actionCodeSettings.handleCodeInApp = true + + try checkSendPasswordResetWithLinkDomain( + customAuthDomain: kCustomAuthDomain, + actionCodeSettings: actionCodeSettings, + expectedLinkDomain: kActionCodeSettingsLinkDomain, + description: #function + ) + } + + /** @fn testSendPasswordResetEmailWithActionCodeSettingsLinkDomainNil + @brief Tests the flow of a successful @c sendPasswordReset call with actionCodeSettings and + linkDomain explicitly nil. + */ + func testSendPasswordResetEmailWithActionCodeSettingsLinkDomainNil() throws { + let kCustomAuthDomain = "test.page.link" + auth.customAuthDomain = kCustomAuthDomain + + let actionCodeSettings = ActionCodeSettings() + actionCodeSettings.linkDomain = nil // Explicitly nil + actionCodeSettings.url = + URL(string: "https://some.other.domain/_next/verify?mode=resetPassword&oobCode=oobCode")! + actionCodeSettings.handleCodeInApp = true + + try checkSendPasswordResetWithLinkDomain( + customAuthDomain: kCustomAuthDomain, + actionCodeSettings: actionCodeSettings, + expectedLinkDomain: kCustomAuthDomain, + description: #function + ) + } + + /** @fn testSendPasswordResetEmailWithCustomAuthDomain + @brief Tests the flow of a successful @c sendPasswordReset call with custom auth domain. + */ + func testSendPasswordResetEmailWithCustomAuthDomain() throws { + let kCustomAuthDomain = "test.page.link" + try checkSendPasswordResetWithLinkDomain( + customAuthDomain: kCustomAuthDomain, + actionCodeSettings: nil, + expectedLinkDomain: kCustomAuthDomain, + description: #function + ) + } + + private func checkSendPasswordResetWithLinkDomain(customAuthDomain: String?, + actionCodeSettings: ActionCodeSettings?, + expectedLinkDomain: String?, + description: String) throws { + let expectation = self.expectation(description: description) + if let customAuthDomain = customAuthDomain { + auth.customAuthDomain = customAuthDomain + } // 1. Setup respond block to test and fake send request. rpcIssuer.respondBlock = { @@ -1599,11 +1674,12 @@ class AuthTests: RPCBaseTests { let request = try XCTUnwrap(self.rpcIssuer.request as? GetOOBConfirmationCodeRequest) XCTAssertEqual(request.email, self.kEmail) XCTAssertEqual(request.apiKey, AuthTests.kFakeAPIKey) + XCTAssertEqual(request.linkDomain, expectedLinkDomain) // 3. Send the response from the fake backend. return try self.rpcIssuer.respond(withJSON: [:]) } - auth?.sendPasswordReset(withEmail: kEmail) { error in + auth?.sendPasswordReset(withEmail: kEmail, actionCodeSettings: actionCodeSettings) { error in // 4. After the response triggers the callback, verify success. XCTAssertTrue(Thread.isMainThread) XCTAssertNil(error)