Kaynağa Gözat

Use sign up endpoint for link with email password (#11925)

renkelvin 2 yıl önce
ebeveyn
işleme
b7fd1697dd

+ 3 - 0
FirebaseAuth/CHANGELOG.md

@@ -1,3 +1,6 @@
+# 10.17.0
+- [fixed] Fix a bug where anonymous account can't be linked with email password credential. (#11911)
+
 # 10.16.0
 - [added] Added custom auth domain support in recaptcha v2 authentication flows. (#7553)
 

+ 1 - 6
FirebaseAuth/Sources/Auth/FIRAuth.m

@@ -35,7 +35,6 @@
 #import "FirebaseAuth/Sources/AuthProvider/FIRAuthCredential_Internal.h"
 #import "FirebaseAuth/Sources/AuthProvider/GameCenter/FIRGameCenterAuthCredential.h"
 #import "FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthCredential_Internal.h"
-#import "FirebaseAuth/Sources/Backend/FIRAuthBackend.h"
 #import "FirebaseAuth/Sources/Backend/FIRAuthRequestConfiguration.h"
 #import "FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIRequest.h"
 #import "FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIResponse.h"
@@ -165,11 +164,6 @@ static NSString *const kVerifyAndChangeEmailRequestType = @"VERIFY_AND_CHANGE_EM
  */
 static NSString *const kRevertSecondFactorAdditionRequestType = @"REVERT_SECOND_FACTOR_ADDITION";
 
-/** @var kMissingRecaptchaTokenErrorPrefix
-    @brief The prefix of the error message of missing recaptcha token during authenticating.
- */
-static NSString *const kMissingRecaptchaTokenErrorPrefix = @"MISSING_RECAPTCHA_TOKEN";
-
 /** @var kMissingPasswordReason
     @brief The reason why the @c FIRAuthErrorCodeWeakPassword error is thrown.
     @remarks This error message will be localized in the future.
@@ -1994,6 +1988,7 @@ static NSMutableDictionary *gKeychainServiceNameForAppName;
       [[FIRSignUpNewUserRequest alloc] initWithEmail:email
                                             password:password
                                          displayName:nil
+                                             idToken:nil
                                 requestConfiguration:_requestConfiguration];
   if (![request.password length]) {
     completion(

+ 1 - 0
FirebaseAuth/Sources/Auth/FIRAuth_Internal.h

@@ -16,6 +16,7 @@
 
 #import <Foundation/Foundation.h>
 #import "FirebaseAuth/Interop/FIRAuthInterop.h"
+#import "FirebaseAuth/Sources/Backend/FIRAuthBackend.h"
 #import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuth.h"
 #import "FirebaseCore/Extension/FIRLogger.h"
 

+ 6 - 0
FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserRequest.h

@@ -38,6 +38,11 @@ NS_ASSUME_NONNULL_BEGIN
  */
 @property(nonatomic, copy, nullable) NSString *displayName;
 
+/** @property idToken
+    @brief The idToken of the user.
+ */
+@property(nonatomic, copy, nullable) NSString *idToken;
+
 /** @property captchaResponse
     @brief Response to the captcha.
  */
@@ -74,6 +79,7 @@ NS_ASSUME_NONNULL_BEGIN
 - (nullable instancetype)initWithEmail:(nullable NSString *)email
                               password:(nullable NSString *)password
                            displayName:(nullable NSString *)displayName
+                               idToken:(nullable NSString *)idToken
                   requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration
     NS_DESIGNATED_INITIALIZER;
 

+ 11 - 0
FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserRequest.m

@@ -38,6 +38,11 @@ static NSString *const kPasswordKey = @"password";
  */
 static NSString *const kDisplayNameKey = @"displayName";
 
+/** @var kIDToken
+    @brief The key for the "kIDToken" value in the request.
+ */
+static NSString *const kIDToken = @"idToken";
+
 /** @var kCaptchaResponseKey
     @brief The key for the "captchaResponse" value in the request.
  */
@@ -68,12 +73,14 @@ static NSString *const kTenantIDKey = @"tenantId";
 - (nullable instancetype)initWithEmail:(nullable NSString *)email
                               password:(nullable NSString *)password
                            displayName:(nullable NSString *)displayName
+                               idToken:(nullable NSString *)idToken
                   requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration {
   self = [super initWithEndpoint:kSignupNewUserEndpoint requestConfiguration:requestConfiguration];
   if (self) {
     _email = [email copy];
     _password = [password copy];
     _displayName = [displayName copy];
+    _idToken = [idToken copy];
     _returnSecureToken = YES;
   }
   return self;
@@ -84,6 +91,7 @@ static NSString *const kTenantIDKey = @"tenantId";
   self = [self initWithEmail:nil
                     password:nil
                  displayName:nil
+                     idToken:nil
         requestConfiguration:requestConfiguration];
   return self;
 }
@@ -99,6 +107,9 @@ static NSString *const kTenantIDKey = @"tenantId";
   if (_displayName) {
     postBody[kDisplayNameKey] = _displayName;
   }
+  if (_idToken) {
+    postBody[kIDToken] = _idToken;
+  }
   if (_captchaResponse) {
     postBody[kCaptchaResponseKey] = _captchaResponse;
   }

+ 110 - 12
FirebaseAuth/Sources/User/FIRUser.m

@@ -43,6 +43,8 @@
 #import "FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoResponse.h"
 #import "FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterRequest.h"
 #import "FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterResponse.h"
+#import "FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserRequest.h"
+#import "FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserResponse.h"
 #import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.h"
 #import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionResponse.h"
 #import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenRequest.h"
@@ -61,9 +63,9 @@
 #import "FirebaseAuth/Sources/Utilities/FIRAuthWebUtils.h"
 
 #if TARGET_OS_IOS
-#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneAuthProvider.h"
-
 #import "FirebaseAuth/Sources/AuthProvider/Phone/FIRPhoneAuthCredential_Internal.h"
+#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneAuthProvider.h"
+#import "FirebaseAuth/Sources/Utilities/FIRAuthRecaptchaVerifier.h"
 #endif
 
 NS_ASSUME_NONNULL_BEGIN
@@ -582,7 +584,6 @@ static void callInMainThreadWithAuthDataResultAndError(
 }
 
 #pragma mark -
-
 /** @fn updateEmail:password:callback:
     @brief Updates email address and/or password for the current user.
     @remarks May fail if there is already an email/password-based account for the same email
@@ -1079,6 +1080,109 @@ static void callInMainThreadWithAuthDataResultAndError(
   });
 }
 
+- (void)linkWithEmailPassword:(FIREmailPasswordAuthCredential *)credential
+                   authResult:(FIRAuthDataResult *)authResult
+                   completion:(nullable FIRAuthDataResultCallback)completion {
+  [self internalGetTokenWithCallback:^(NSString *_Nullable accessToken, NSError *_Nullable error) {
+    FIRAuthRequestConfiguration *requestConfiguration = self.auth.requestConfiguration;
+    FIRSignUpNewUserRequest *request =
+        [[FIRSignUpNewUserRequest alloc] initWithEmail:credential.email
+                                              password:credential.password
+                                           displayName:nil
+                                               idToken:accessToken
+                                  requestConfiguration:requestConfiguration];
+    FIRSignupNewUserCallback signUpNewUserCallback = ^(FIRSignUpNewUserResponse *_Nullable response,
+                                                       NSError *_Nullable error) {
+      if (error) {
+        [self signOutIfTokenIsInvalidWithError:error];
+        callInMainThreadWithAuthDataResultAndError(completion, nil, error);
+      } else {
+        // Update the new token and refresh user info again.
+        self->_tokenService = [[FIRSecureTokenService alloc]
+            initWithRequestConfiguration:requestConfiguration
+                             accessToken:response.IDToken
+               accessTokenExpirationDate:response.approximateExpirationDate
+                            refreshToken:response.refreshToken];
+
+        [self internalGetTokenWithCallback:^(NSString *_Nullable accessToken,
+                                             NSError *_Nullable error) {
+          if (error) {
+            callInMainThreadWithAuthDataResultAndError(completion, nil, error);
+            return;
+          }
+          FIRGetAccountInfoRequest *getAccountInfoRequest =
+              [[FIRGetAccountInfoRequest alloc] initWithAccessToken:accessToken
+                                               requestConfiguration:requestConfiguration];
+          [FIRAuthBackend
+              getAccountInfo:getAccountInfoRequest
+                    callback:^(FIRGetAccountInfoResponse *_Nullable response,
+                               NSError *_Nullable error) {
+                      if (error) {
+                        [self signOutIfTokenIsInvalidWithError:error];
+                        callInMainThreadWithAuthDataResultAndError(completion, nil, error);
+                        return;
+                      }
+                      self.anonymous = NO;
+                      [self updateWithGetAccountInfoResponse:response];
+                      NSError *keychainError;
+                      if (![self updateKeychain:&keychainError]) {
+                        callInMainThreadWithAuthDataResultAndError(completion, nil, keychainError);
+                        return;
+                      }
+                      [self signOutIfTokenIsInvalidWithError:error];
+                      callInMainThreadWithAuthDataResultAndError(completion, authResult, nil);
+                    }];
+        }];
+      }
+    };
+
+#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST && (!defined(TARGET_OS_VISION) || !TARGET_OS_VISION)
+    if ([[FIRAuthRecaptchaVerifier sharedRecaptchaVerifier:self.auth]
+            enablementStatusForProvider:FIRAuthRecaptchaProviderPassword]) {
+      [[FIRAuthRecaptchaVerifier sharedRecaptchaVerifier:self.auth]
+          injectRecaptchaFields:request
+                       provider:FIRAuthRecaptchaProviderPassword
+                         action:FIRAuthRecaptchaActionSignUpPassword
+                     completion:^(
+                         FIRIdentityToolkitRequest<FIRAuthRPCRequest> *requestWithRecaptchaToken) {
+                       [FIRAuthBackend
+                           signUpNewUser:(FIRSignUpNewUserRequest *)requestWithRecaptchaToken
+                                callback:signUpNewUserCallback];
+                     }];
+    } else {
+      [FIRAuthBackend
+          signUpNewUser:request
+               callback:^(FIRSignUpNewUserResponse *_Nullable response, NSError *_Nullable error) {
+                 if (!error) {
+                   signUpNewUserCallback(response, nil);
+                   return;
+                 }
+                 NSError *underlyingError = [error.userInfo objectForKey:NSUnderlyingErrorKey];
+                 if (error.code == FIRAuthErrorCodeInternalError &&
+                     [[underlyingError.userInfo
+                         objectForKey:FIRAuthErrorUserInfoDeserializedResponseKey][@"message"]
+                         hasPrefix:kMissingRecaptchaTokenErrorPrefix]) {
+                   [[FIRAuthRecaptchaVerifier sharedRecaptchaVerifier:self.auth]
+                       injectRecaptchaFields:request
+                                    provider:FIRAuthRecaptchaProviderPassword
+                                      action:FIRAuthRecaptchaActionSignUpPassword
+                                  completion:^(FIRIdentityToolkitRequest<FIRAuthRPCRequest>
+                                                   *requestWithRecaptchaToken) {
+                                    [FIRAuthBackend signUpNewUser:(FIRSignUpNewUserRequest *)
+                                                                      requestWithRecaptchaToken
+                                                         callback:signUpNewUserCallback];
+                                  }];
+                 } else {
+                   signUpNewUserCallback(nil, error);
+                 }
+               }];
+    }
+#else
+[FIRAuthBackend signUpNewUser:request callback:signUpNewUserCallback];
+#endif
+  }];
+}
+
 - (void)linkWithCredential:(FIRAuthCredential *)credential
                 completion:(nullable FIRAuthDataResultCallback)completion {
   dispatch_async(FIRAuthGlobalWorkQueue(), ^{
@@ -1098,15 +1202,9 @@ static void callInMainThreadWithAuthDataResultAndError(
       FIREmailPasswordAuthCredential *emailPasswordCredential =
           (FIREmailPasswordAuthCredential *)credential;
       if (emailPasswordCredential.password) {
-        [self updateEmail:emailPasswordCredential.email
-                 password:emailPasswordCredential.password
-                 callback:^(NSError *error) {
-                   if (error) {
-                     callInMainThreadWithAuthDataResultAndError(completion, nil, error);
-                   } else {
-                     callInMainThreadWithAuthDataResultAndError(completion, result, nil);
-                   }
-                 }];
+        [self linkWithEmailPassword:emailPasswordCredential
+                         authResult:result
+                         completion:completion];
       } else {
         [self internalGetTokenWithCallback:^(NSString *_Nullable accessToken,
                                              NSError *_Nullable error) {

+ 5 - 0
FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h

@@ -23,6 +23,11 @@
 
 NS_ASSUME_NONNULL_BEGIN
 
+/** @var kMissingRecaptchaTokenErrorPrefix
+    @brief The prefix of the error message of missing recaptcha token during authenticating.
+ */
+static NSString *const kMissingRecaptchaTokenErrorPrefix = @"MISSING_RECAPTCHA_TOKEN";
+
 /** @class FIRAuthErrorUtils
     @brief Utility class used to construct @c NSError instances.
  */

+ 7 - 0
FirebaseAuth/Tests/Unit/FIRAuthTests.m

@@ -138,6 +138,11 @@ static NSString *const kLocalID = @"LOCAL_ID";
  */
 static NSString *const kDisplayName = @"User Doe";
 
+/** @var kIDToken
+    @brief The fake id token.
+ */
+static NSString *const kIDToken = @"IDToken";
+
 /** @var kFakeGivenName
     @brief The fake user given name.
  */
@@ -1818,6 +1823,7 @@ static NSString *const kFakeRecaptchaVersion = @"RecaptchaVersion";
       [[FIRSignUpNewUserRequest alloc] initWithEmail:kEmail
                                             password:kFakePassword
                                          displayName:kDisplayName
+                                             idToken:kIDToken
                                 requestConfiguration:[FIRAuth auth].requestConfiguration];
   [constRequestWithRecaptchaToken injectRecaptchaFields:kFakeRecaptchaResponse
                                        recaptchaVersion:kFakeRecaptchaVersion];
@@ -1867,6 +1873,7 @@ static NSString *const kFakeRecaptchaVersion = @"RecaptchaVersion";
       [[FIRSignUpNewUserRequest alloc] initWithEmail:kEmail
                                             password:kFakePassword
                                          displayName:kDisplayName
+                                             idToken:kIDToken
                                 requestConfiguration:[FIRAuth auth].requestConfiguration];
   [constRequestWithRecaptchaToken injectRecaptchaFields:kFakeRecaptchaResponse
                                        recaptchaVersion:kFakeRecaptchaVersion];

+ 12 - 0
FirebaseAuth/Tests/Unit/FIRSignUpNewUserRequestTests.m

@@ -60,6 +60,16 @@ static NSString *const kDisplayNameKey = @"displayName";
  */
 static NSString *const kTestDisplayName = @"DisplayName";
 
+/** @var kIDTokenKey
+    @brief the name of the "kIDTokenKey" property in the request.
+ */
+static NSString *const kIDTokenKey = @"idToken";
+
+/** @var kTestIDToken
+    @brief Testing id token.
+ */
+static NSString *const kTestIDToken = @"testIDToken";
+
 /** @var kPasswordKey
     @brief the name of the "password" property in the request.
  */
@@ -167,6 +177,7 @@ static NSString *const kReturnSecureTokenKey = @"returnSecureToken";
       [[FIRSignUpNewUserRequest alloc] initWithEmail:kTestEmail
                                             password:kTestPassword
                                          displayName:kTestDisplayName
+                                             idToken:kTestIDToken
                                 requestConfiguration:_requestConfiguration];
   [FIRAuthBackend
       signUpNewUser:request
@@ -190,6 +201,7 @@ static NSString *const kReturnSecureTokenKey = @"returnSecureToken";
       [[FIRSignUpNewUserRequest alloc] initWithEmail:kTestEmail
                                             password:kTestPassword
                                          displayName:kTestDisplayName
+                                             idToken:kTestIDToken
                                 requestConfiguration:_requestConfiguration];
   request.captchaResponse = kTestCaptchaResponse;
   request.clientType = kTestClientType;

+ 1 - 0
FirebaseAuth/Tests/Unit/FIRSignUpNewUserResponseTests.m

@@ -159,6 +159,7 @@ static const double kAllowedTimeDifference = 0.1;
       [[FIRSignUpNewUserRequest alloc] initWithEmail:kTestEmail
                                             password:kTestPassword
                                          displayName:kTestDisplayName
+                                             idToken:kTestIDToken
                                 requestConfiguration:_requestConfiguration];
 
   __block BOOL callbackInvoked;

+ 66 - 59
FirebaseAuth/Tests/Unit/FIRUserTests.m

@@ -39,6 +39,7 @@
 #import "FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenResponse.h"
 #import "FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoRequest.h"
 #import "FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoResponse.h"
+#import "FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserRequest.h"
 #import "FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserResponse.h"
 #import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.h"
 #import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionResponse.h"
@@ -2251,7 +2252,6 @@ static NSString *const kFakeWebSignInUserInteractionFailureReason = @"fake_reaso
                              profile:[[self class] googleProfile]
                      providerIDToken:kFacebookIDToken
                  providerAccessToken:kFacebookAccessToken];
-
   XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
   [[FIRAuth auth] signOut:NULL];
   FIRAuthCredential *facebookCredential =
@@ -2268,31 +2268,38 @@ static NSString *const kFakeWebSignInUserInteractionFailureReason = @"fake_reaso
                                         FIRFacebookAuthProviderID);
                   XCTAssertNil(error);
 
-                  id mockGetAccountInfoResponseUser =
-                      OCMClassMock([FIRGetAccountInfoResponseUser class]);
-                  OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
-                  OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
-                  OCMStub([mockGetAccountInfoResponseUser displayName])
-                      .andReturn(kEmailDisplayName);
-                  OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
-                  // Get account info is expected to be invoked twice.
-                  [self
-                      expectGetAccountInfoWithMockUserInfoResponse:mockGetAccountInfoResponseUser];
-                  [self
-                      expectGetAccountInfoWithMockUserInfoResponse:mockGetAccountInfoResponseUser];
-
-                  OCMExpect([self->_mockBackend setAccountInfo:[OCMArg any] callback:[OCMArg any]])
-                      .andCallBlock2(^(FIRSetAccountInfoRequest *_Nullable request,
-                                       FIRSetAccountInfoResponseCallback callback) {
-                        XCTAssertEqualObjects(request.APIKey, kAPIKey);
-                        XCTAssertEqualObjects(request.accessToken, kAccessToken);
+                  OCMExpect([self->_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]])
+                      .andCallBlock2(^(FIRSignUpNewUserRequest *_Nullable request,
+                                       FIRSignupNewUserCallback callback) {
+                        XCTAssertEqualObjects(request.email, kEmail);
                         XCTAssertEqualObjects(request.password, kFakePassword);
-                        XCTAssertNil(request.localID);
                         XCTAssertNil(request.displayName);
                         dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
-                          id mockSetAccountInfoResponse =
-                              OCMClassMock([FIRSetAccountInfoResponse class]);
-                          callback(mockSetAccountInfoResponse, nil);
+                          id mockSignUpNewUserResponse =
+                              OCMClassMock([FIRSignUpNewUserResponse class]);
+                          [self stubTokensWithMockResponse:mockSignUpNewUserResponse];
+                          callback(mockSignUpNewUserResponse, nil);
+                        });
+                      });
+
+                  OCMExpect([self->_mockBackend getAccountInfo:[OCMArg any] callback:[OCMArg any]])
+                      .andCallBlock2(^(FIRGetAccountInfoRequest *_Nullable request,
+                                       FIRGetAccountInfoResponseCallback callback) {
+                        dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
+                          id mockGetAccountInfoResponseUser =
+                              OCMClassMock([FIRGetAccountInfoResponseUser class]);
+                          OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
+                          OCMStub([mockGetAccountInfoResponseUser displayName])
+                              .andReturn(kEmailDisplayName);
+                          OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
+                          OCMStub([mockGetAccountInfoResponseUser passwordHash])
+                              .andReturn(kPasswordHash);
+                          id mockGetAccountInfoResponse =
+                              OCMClassMock([FIRGetAccountInfoResponse class]);
+                          OCMStub([mockGetAccountInfoResponse users]).andReturn(@[
+                            mockGetAccountInfoResponseUser
+                          ]);
+                          callback(mockGetAccountInfoResponse, nil);
                         });
                       });
 
@@ -2343,31 +2350,38 @@ static NSString *const kFakeWebSignInUserInteractionFailureReason = @"fake_reaso
                                         FIRFacebookAuthProviderID);
                   XCTAssertNil(error);
 
-                  id mockGetAccountInfoResponseUser =
-                      OCMClassMock([FIRGetAccountInfoResponseUser class]);
-                  OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
-                  OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
-                  OCMStub([mockGetAccountInfoResponseUser displayName])
-                      .andReturn(kEmailDisplayName);
-                  OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
-                  // Get account info is expected to be invoked twice.
-                  [self
-                      expectGetAccountInfoWithMockUserInfoResponse:mockGetAccountInfoResponseUser];
-                  [self
-                      expectGetAccountInfoWithMockUserInfoResponse:mockGetAccountInfoResponseUser];
-
-                  OCMExpect([self->_mockBackend setAccountInfo:[OCMArg any] callback:[OCMArg any]])
-                      .andCallBlock2(^(FIRSetAccountInfoRequest *_Nullable request,
-                                       FIRSetAccountInfoResponseCallback callback) {
-                        XCTAssertEqualObjects(request.APIKey, kAPIKey);
-                        XCTAssertEqualObjects(request.accessToken, kAccessToken);
+                  OCMExpect([self->_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]])
+                      .andCallBlock2(^(FIRSignUpNewUserRequest *_Nullable request,
+                                       FIRSignupNewUserCallback callback) {
+                        XCTAssertEqualObjects(request.email, kEmail);
                         XCTAssertEqualObjects(request.password, kFakePassword);
-                        XCTAssertNil(request.localID);
                         XCTAssertNil(request.displayName);
                         dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
-                          id mockSetAccountInfoResponse =
-                              OCMClassMock([FIRSetAccountInfoResponse class]);
-                          callback(mockSetAccountInfoResponse, nil);
+                          id mockSignUpNewUserResponse =
+                              OCMClassMock([FIRSignUpNewUserResponse class]);
+                          [self stubTokensWithMockResponse:mockSignUpNewUserResponse];
+                          callback(mockSignUpNewUserResponse, nil);
+                        });
+                      });
+
+                  OCMExpect([self->_mockBackend getAccountInfo:[OCMArg any] callback:[OCMArg any]])
+                      .andCallBlock2(^(FIRGetAccountInfoRequest *_Nullable request,
+                                       FIRGetAccountInfoResponseCallback callback) {
+                        dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
+                          id mockGetAccountInfoResponseUser =
+                              OCMClassMock([FIRGetAccountInfoResponseUser class]);
+                          OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
+                          OCMStub([mockGetAccountInfoResponseUser displayName])
+                              .andReturn(kEmailDisplayName);
+                          OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
+                          OCMStub([mockGetAccountInfoResponseUser passwordHash])
+                              .andReturn(kPasswordHash);
+                          id mockGetAccountInfoResponse =
+                              OCMClassMock([FIRGetAccountInfoResponse class]);
+                          OCMStub([mockGetAccountInfoResponse users]).andReturn(@[
+                            mockGetAccountInfoResponseUser
+                          ]);
+                          callback(mockGetAccountInfoResponse, nil);
                         });
                       });
 
@@ -2429,11 +2443,11 @@ static NSString *const kFakeWebSignInUserInteractionFailureReason = @"fake_reaso
                                         FIRFacebookAuthProviderID);
                   XCTAssertNil(error);
 
-                  OCMExpect([self->_mockBackend getAccountInfo:[OCMArg any] callback:[OCMArg any]])
-                      .andCallBlock2(^(FIRGetAccountInfoRequest *_Nullable request,
-                                       FIRGetAccountInfoResponseCallback callback) {
-                        XCTAssertEqualObjects(request.APIKey, kAPIKey);
-                        XCTAssertEqualObjects(request.accessToken, kAccessToken);
+                  OCMExpect([self->_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]])
+                      .andCallBlock2(^(FIRSignUpNewUserRequest *_Nullable request,
+                                       FIRSignupNewUserCallback callback) {
+                        XCTAssertEqualObjects(request.email, kEmail);
+                        XCTAssertEqualObjects(request.password, kFakePassword);
                         dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
                           callback(nil, [FIRAuthErrorUtils tooManyRequestsErrorWithMessage:nil]);
                         });
@@ -2484,15 +2498,8 @@ static NSString *const kFakeWebSignInUserInteractionFailureReason = @"fake_reaso
                                         FIRFacebookAuthProviderID);
                   XCTAssertNil(error);
 
-                  OCMExpect([self->_mockBackend getAccountInfo:[OCMArg any] callback:[OCMArg any]])
-                      .andCallBlock2(^(FIRGetAccountInfoRequest *_Nullable request,
-                                       FIRGetAccountInfoResponseCallback callback) {
-                        XCTAssertEqualObjects(request.APIKey, kAPIKey);
-                        XCTAssertEqualObjects(request.accessToken, kAccessToken);
-                        dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
-                          callback(nil, [FIRAuthErrorUtils userTokenExpiredErrorWithMessage:nil]);
-                        });
-                      });
+                  OCMExpect([self->_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]])
+                      .andDispatchError2([FIRAuthErrorUtils userTokenExpiredErrorWithMessage:nil]);
 
                   FIRAuthCredential *linkEmailCredential =
                       [FIREmailAuthProvider credentialWithEmail:kEmail password:kFakePassword];