aboutsummaryrefslogtreecommitdiffhomepage
path: root/Firebase/Auth
diff options
context:
space:
mode:
Diffstat (limited to 'Firebase/Auth')
-rw-r--r--Firebase/Auth/CHANGELOG.md62
-rw-r--r--Firebase/Auth/Docs/threading.md119
-rw-r--r--Firebase/Auth/FirebaseAuth.podspec56
-rw-r--r--Firebase/Auth/README.md8
-rw-r--r--Firebase/Auth/Source/AuthProviders/EmailPassword/FIREmailAuthProvider.h63
-rw-r--r--Firebase/Auth/Source/AuthProviders/EmailPassword/FIREmailAuthProvider.m35
-rw-r--r--Firebase/Auth/Source/AuthProviders/EmailPassword/FIREmailPasswordAuthCredential.h48
-rw-r--r--Firebase/Auth/Source/AuthProviders/EmailPassword/FIREmailPasswordAuthCredential.m51
-rw-r--r--Firebase/Auth/Source/AuthProviders/EmailPassword/FIREmailPasswordAuthProvider.h49
-rw-r--r--Firebase/Auth/Source/AuthProviders/EmailPassword/FIREmailPasswordAuthProvider.m35
-rw-r--r--Firebase/Auth/Source/AuthProviders/Facebook/FIRFacebookAuthCredential.h36
-rw-r--r--Firebase/Auth/Source/AuthProviders/Facebook/FIRFacebookAuthCredential.m51
-rw-r--r--Firebase/Auth/Source/AuthProviders/Facebook/FIRFacebookAuthProvider.h51
-rw-r--r--Firebase/Auth/Source/AuthProviders/Facebook/FIRFacebookAuthProvider.m36
-rw-r--r--Firebase/Auth/Source/AuthProviders/GitHub/FIRGitHubAuthCredential.h41
-rw-r--r--Firebase/Auth/Source/AuthProviders/GitHub/FIRGitHubAuthCredential.m49
-rw-r--r--Firebase/Auth/Source/AuthProviders/GitHub/FIRGitHubAuthProvider.h51
-rw-r--r--Firebase/Auth/Source/AuthProviders/GitHub/FIRGitHubAuthProvider.m36
-rw-r--r--Firebase/Auth/Source/AuthProviders/Google/FIRGoogleAuthCredential.h38
-rw-r--r--Firebase/Auth/Source/AuthProviders/Google/FIRGoogleAuthCredential.m54
-rw-r--r--Firebase/Auth/Source/AuthProviders/Google/FIRGoogleAuthProvider.h53
-rw-r--r--Firebase/Auth/Source/AuthProviders/Google/FIRGoogleAuthProvider.m37
-rw-r--r--Firebase/Auth/Source/AuthProviders/OAuth/FIROAuthCredential.h55
-rw-r--r--Firebase/Auth/Source/AuthProviders/OAuth/FIROAuthCredential.m50
-rw-r--r--Firebase/Auth/Source/AuthProviders/OAuth/FIROAuthProvider.h64
-rw-r--r--Firebase/Auth/Source/AuthProviders/OAuth/FIROAuthProvider.m42
-rw-r--r--Firebase/Auth/Source/AuthProviders/Phone/FIRPhoneAuthCredential.h37
-rw-r--r--Firebase/Auth/Source/AuthProviders/Phone/FIRPhoneAuthCredential.m65
-rw-r--r--Firebase/Auth/Source/AuthProviders/Phone/FIRPhoneAuthCredential_Internal.h70
-rw-r--r--Firebase/Auth/Source/AuthProviders/Phone/FIRPhoneAuthProvider.h90
-rw-r--r--Firebase/Auth/Source/AuthProviders/Phone/FIRPhoneAuthProvider.m213
-rw-r--r--Firebase/Auth/Source/AuthProviders/Phone/NSString+FIRAuth.h36
-rw-r--r--Firebase/Auth/Source/AuthProviders/Phone/NSString+FIRAuth.m36
-rw-r--r--Firebase/Auth/Source/AuthProviders/Twitter/FIRTwitterAuthCredential.h48
-rw-r--r--Firebase/Auth/Source/AuthProviders/Twitter/FIRTwitterAuthCredential.m51
-rw-r--r--Firebase/Auth/Source/AuthProviders/Twitter/FIRTwitterAuthProvider.h52
-rw-r--r--Firebase/Auth/Source/AuthProviders/Twitter/FIRTwitterAuthProvider.m36
-rw-r--r--Firebase/Auth/Source/FIRActionCodeSettings.m39
-rw-r--r--Firebase/Auth/Source/FIRAdditionalUserInfo.h59
-rw-r--r--Firebase/Auth/Source/FIRAdditionalUserInfo.m98
-rw-r--r--Firebase/Auth/Source/FIRAuth.h612
-rw-r--r--Firebase/Auth/Source/FIRAuth.m1252
-rw-r--r--Firebase/Auth/Source/FIRAuthAPNSToken.m34
-rw-r--r--Firebase/Auth/Source/FIRAuthAPNSTokenManager.m255
-rw-r--r--Firebase/Auth/Source/FIRAuthAPNSTokenType.h42
-rw-r--r--Firebase/Auth/Source/FIRAuthAppCredential.m64
-rw-r--r--Firebase/Auth/Source/FIRAuthAppCredentialManager.m164
-rw-r--r--Firebase/Auth/Source/FIRAuthAppDelegateProxy.m245
-rw-r--r--Firebase/Auth/Source/FIRAuthCredential.h43
-rw-r--r--Firebase/Auth/Source/FIRAuthCredential.m42
-rw-r--r--Firebase/Auth/Source/FIRAuthDataResult.h51
-rw-r--r--Firebase/Auth/Source/FIRAuthDataResult.m69
-rw-r--r--Firebase/Auth/Source/FIRAuthDispatcher.m46
-rw-r--r--Firebase/Auth/Source/FIRAuthErrorUtils.m794
-rw-r--r--Firebase/Auth/Source/FIRAuthErrors.h258
-rw-r--r--Firebase/Auth/Source/FIRAuthExceptionUtils.h41
-rw-r--r--Firebase/Auth/Source/FIRAuthExceptionUtils.m36
-rw-r--r--Firebase/Auth/Source/FIRAuthGlobalWorkQueue.m26
-rw-r--r--Firebase/Auth/Source/FIRAuthKeychain.m256
-rw-r--r--Firebase/Auth/Source/FIRAuthNotificationManager.m175
-rw-r--r--Firebase/Auth/Source/FIRAuthProvider.m38
-rw-r--r--Firebase/Auth/Source/FIRAuthSerialTaskQueue.m52
-rw-r--r--Firebase/Auth/Source/FIRAuthSwiftNameSupport.h29
-rw-r--r--Firebase/Auth/Source/FIRAuthUserDefaultsStorage.m78
-rw-r--r--Firebase/Auth/Source/FIRSecureTokenService.h96
-rw-r--r--Firebase/Auth/Source/FIRSecureTokenService.m214
-rw-r--r--Firebase/Auth/Source/FIRUser.h463
-rw-r--r--Firebase/Auth/Source/FIRUser.m1170
-rw-r--r--Firebase/Auth/Source/FIRUserInfo.h62
-rw-r--r--Firebase/Auth/Source/FIRUserInfoImpl.h61
-rw-r--r--Firebase/Auth/Source/FIRUserInfoImpl.m127
-rw-r--r--Firebase/Auth/Source/FirebaseAuth.h27
-rwxr-xr-xFirebase/Auth/Source/FirebaseAuthVersion.h27
-rw-r--r--Firebase/Auth/Source/FirebaseAuthVersion.m26
-rw-r--r--Firebase/Auth/Source/Private/FIRActionCodeSettings.h91
-rw-r--r--Firebase/Auth/Source/Private/FIRAdditionalUserInfo_Internal.h46
-rw-r--r--Firebase/Auth/Source/Private/FIRAuthAPNSToken.h54
-rw-r--r--Firebase/Auth/Source/Private/FIRAuthAPNSTokenManager.h69
-rw-r--r--Firebase/Auth/Source/Private/FIRAuthAppCredential.h53
-rw-r--r--Firebase/Auth/Source/Private/FIRAuthAppCredentialManager.h85
-rw-r--r--Firebase/Auth/Source/Private/FIRAuthAppDelegateProxy.h74
-rw-r--r--Firebase/Auth/Source/Private/FIRAuthCredential_Internal.h41
-rw-r--r--Firebase/Auth/Source/Private/FIRAuthDataResult_Internal.h34
-rw-r--r--Firebase/Auth/Source/Private/FIRAuthDispatcher.h63
-rw-r--r--Firebase/Auth/Source/Private/FIRAuthErrorUtils.h418
-rw-r--r--Firebase/Auth/Source/Private/FIRAuthGlobalWorkQueue.h31
-rw-r--r--Firebase/Auth/Source/Private/FIRAuthInternalErrors.h365
-rw-r--r--Firebase/Auth/Source/Private/FIRAuthKeychain.h70
-rw-r--r--Firebase/Auth/Source/Private/FIRAuthNotificationManager.h71
-rw-r--r--Firebase/Auth/Source/Private/FIRAuthSerialTaskQueue.h50
-rw-r--r--Firebase/Auth/Source/Private/FIRAuthUserDefaultsStorage.h47
-rw-r--r--Firebase/Auth/Source/Private/FIRAuth_Internal.h123
-rw-r--r--Firebase/Auth/Source/Private/FIRUser_Internal.h80
-rw-r--r--Firebase/Auth/Source/RPCs/FIRAuthBackend.h496
-rw-r--r--Firebase/Auth/Source/RPCs/FIRAuthBackend.m943
-rw-r--r--Firebase/Auth/Source/RPCs/FIRAuthRPCRequest.h40
-rw-r--r--Firebase/Auth/Source/RPCs/FIRAuthRPCResponse.h49
-rw-r--r--Firebase/Auth/Source/RPCs/FIRCreateAuthURIRequest.h86
-rw-r--r--Firebase/Auth/Source/RPCs/FIRCreateAuthURIRequest.m95
-rw-r--r--Firebase/Auth/Source/RPCs/FIRCreateAuthURIResponse.h56
-rw-r--r--Firebase/Auth/Source/RPCs/FIRCreateAuthURIResponse.m33
-rw-r--r--Firebase/Auth/Source/RPCs/FIRDeleteAccountRequest.h48
-rw-r--r--Firebase/Auth/Source/RPCs/FIRDeleteAccountRequest.m65
-rw-r--r--Firebase/Auth/Source/RPCs/FIRDeleteAccountResponse.h26
-rw-r--r--Firebase/Auth/Source/RPCs/FIRDeleteAccountResponse.m28
-rw-r--r--Firebase/Auth/Source/RPCs/FIRGetAccountInfoRequest.h51
-rw-r--r--Firebase/Auth/Source/RPCs/FIRGetAccountInfoRequest.m47
-rw-r--r--Firebase/Auth/Source/RPCs/FIRGetAccountInfoResponse.h146
-rw-r--r--Firebase/Auth/Source/RPCs/FIRGetAccountInfoResponse.m94
-rw-r--r--Firebase/Auth/Source/RPCs/FIRGetOOBConfirmationCodeRequest.h87
-rw-r--r--Firebase/Auth/Source/RPCs/FIRGetOOBConfirmationCodeRequest.m135
-rw-r--r--Firebase/Auth/Source/RPCs/FIRGetOOBConfirmationCodeResponse.h35
-rw-r--r--Firebase/Auth/Source/RPCs/FIRGetOOBConfirmationCodeResponse.m38
-rw-r--r--Firebase/Auth/Source/RPCs/FIRIdentityToolkitRequest.h57
-rw-r--r--Firebase/Auth/Source/RPCs/FIRIdentityToolkitRequest.m57
-rw-r--r--Firebase/Auth/Source/RPCs/FIRResetPasswordRequest.h53
-rw-r--r--Firebase/Auth/Source/RPCs/FIRResetPasswordRequest.m56
-rw-r--r--Firebase/Auth/Source/RPCs/FIRResetPasswordResponse.h52
-rw-r--r--Firebase/Auth/Source/RPCs/FIRResetPasswordResponse.m31
-rw-r--r--Firebase/Auth/Source/RPCs/FIRSecureTokenRequest.h109
-rw-r--r--Firebase/Auth/Source/RPCs/FIRSecureTokenRequest.m141
-rw-r--r--Firebase/Auth/Source/RPCs/FIRSecureTokenResponse.h50
-rw-r--r--Firebase/Auth/Source/RPCs/FIRSecureTokenResponse.m70
-rw-r--r--Firebase/Auth/Source/RPCs/FIRSendVerificationCodeRequest.h56
-rw-r--r--Firebase/Auth/Source/RPCs/FIRSendVerificationCodeRequest.m73
-rw-r--r--Firebase/Auth/Source/RPCs/FIRSendVerificationCodeResponse.h32
-rw-r--r--Firebase/Auth/Source/RPCs/FIRSendVerificationCodeResponse.m36
-rw-r--r--Firebase/Auth/Source/RPCs/FIRSetAccountInfoRequest.h149
-rw-r--r--Firebase/Auth/Source/RPCs/FIRSetAccountInfoRequest.m174
-rw-r--r--Firebase/Auth/Source/RPCs/FIRSetAccountInfoResponse.h98
-rw-r--r--Firebase/Auth/Source/RPCs/FIRSetAccountInfoResponse.m61
-rw-r--r--Firebase/Auth/Source/RPCs/FIRSignUpNewUserRequest.h67
-rw-r--r--Firebase/Auth/Source/RPCs/FIRSignUpNewUserRequest.m82
-rw-r--r--Firebase/Auth/Source/RPCs/FIRSignUpNewUserResponse.h44
-rw-r--r--Firebase/Auth/Source/RPCs/FIRSignUpNewUserResponse.m32
-rw-r--r--Firebase/Auth/Source/RPCs/FIRVerifyAssertionRequest.h100
-rw-r--r--Firebase/Auth/Source/RPCs/FIRVerifyAssertionRequest.m142
-rw-r--r--Firebase/Auth/Source/RPCs/FIRVerifyAssertionResponse.h186
-rw-r--r--Firebase/Auth/Source/RPCs/FIRVerifyAssertionResponse.m78
-rw-r--r--Firebase/Auth/Source/RPCs/FIRVerifyClientRequest.h53
-rw-r--r--Firebase/Auth/Source/RPCs/FIRVerifyClientRequest.m63
-rw-r--r--Firebase/Auth/Source/RPCs/FIRVerifyClientResponse.h38
-rw-r--r--Firebase/Auth/Source/RPCs/FIRVerifyClientResponse.m33
-rw-r--r--Firebase/Auth/Source/RPCs/FIRVerifyCustomTokenRequest.h56
-rw-r--r--Firebase/Auth/Source/RPCs/FIRVerifyCustomTokenRequest.m56
-rw-r--r--Firebase/Auth/Source/RPCs/FIRVerifyCustomTokenResponse.h47
-rw-r--r--Firebase/Auth/Source/RPCs/FIRVerifyCustomTokenResponse.m32
-rw-r--r--Firebase/Auth/Source/RPCs/FIRVerifyPasswordRequest.h79
-rw-r--r--Firebase/Auth/Source/RPCs/FIRVerifyPasswordRequest.m91
-rw-r--r--Firebase/Auth/Source/RPCs/FIRVerifyPasswordResponse.h72
-rw-r--r--Firebase/Auth/Source/RPCs/FIRVerifyPasswordResponse.m36
-rw-r--r--Firebase/Auth/Source/RPCs/FIRVerifyPhoneNumberRequest.h78
-rw-r--r--Firebase/Auth/Source/RPCs/FIRVerifyPhoneNumberRequest.m97
-rw-r--r--Firebase/Auth/Source/RPCs/FIRVerifyPhoneNumberResponse.h64
-rw-r--r--Firebase/Auth/Source/RPCs/FIRVerifyPhoneNumberResponse.m42
155 files changed, 16661 insertions, 0 deletions
diff --git a/Firebase/Auth/CHANGELOG.md b/Firebase/Auth/CHANGELOG.md
new file mode 100644
index 0000000..d2eb535
--- /dev/null
+++ b/Firebase/Auth/CHANGELOG.md
@@ -0,0 +1,62 @@
+# 2017-05-17 -- v4.0.0
+- Adds Phone Number Authentication.
+- Adds support for generic OAuth2 identity providers.
+- Adds methods that return additional user data from identity providers if
+ available when authenticating users.
+- Improves session management by automatically refreshing tokens if possible
+ and signing out users if the session is detected invalidated, for example,
+ after the user changed password or deleted account from another device.
+- Fixes an issue that reauthentication creates new user account if the user
+ credential is valid but does not match the currently signed in user.
+- Fixes an issue that the "password" provider is not immediately listed on the
+ client side after adding a password to an account.
+- Changes factory methods to return non-null FIRAuth instances or raises an
+ exception, instead of returning nullable instances.
+- Changes auth state change listener to only be triggered when the user changes.
+- Adds a new listener which is triggered whenever the ID token is changed.
+- Switches ERROR_EMAIL_ALREADY_IN_USE to
+ ERROR_ACCOUNT_EXISTS_WITH_DIFFERENT_CREDENTIAL when the email used in the
+ signInWithCredential: call is already in use by another account.
+- Deprecates FIREmailPasswordAuthProvider in favor of FIREmailAuthProvider.
+- Deprecates getTokenWithCompletion in favor of getIDTokenWithCompletion on
+ FIRUser.
+- Changes Swift API names to better align with Swift convention.
+
+# 2017-02-06 -- v3.1.1
+- Allows handling of additional errors when sending OOB action emails. The
+ server can respond with the following new error messages:
+ INVALID_MESSAGE_PAYLOAD,INVALID_SENDER and INVALID_RECIPIENT_EMAIL.
+- Removes incorrect reference to FIRAuthErrorCodeCredentialTooOld in FIRUser.h.
+- Provides additional error information from server if available.
+
+# 2016-12-13 -- v3.1.0
+- Adds FIRAuth methods that enable the app to follow up with user actions
+ delivered by email, such as verifying email address or reset password.
+- No longer applies the keychain workaround introduced in v3.0.5 on iOS 10.2
+ simulator or above since the issue has been fixed.
+- Fixes nullability compilation warnings when used in Swift.
+- Better reports missing password error.
+
+# 2016-10-24 -- v3.0.6
+- Switches to depend on open sourced GoogleToolboxForMac and GTMSessionFetcher.
+- Improves logging of keychain error when initializing.
+
+# 2016-09-14 -- v3.0.5
+- Works around a keychain issue in iOS 10 simulator.
+- Reports the correct error for invalid email when signing in with email and
+ password.
+
+# 2016-07-18 -- v3.0.4
+- Fixes a race condition bug that could crash the app with an exception from
+ NSURLSession on iOS 9.
+
+# 2016-06-20 -- v3.0.3
+- Adds documentation for all possible errors returned by each method.
+- Improves error handling and messages for a variety of error conditions.
+- Whether or not an user is considered anonymous is now consistent with other
+ platforms.
+- A saved signed in user is now siloed between different Firebase projects
+ within the same app.
+
+# 2016-05-18 -- v3.0.2
+- Initial public release.
diff --git a/Firebase/Auth/Docs/threading.md b/Firebase/Auth/Docs/threading.md
new file mode 100644
index 0000000..2f5b782
--- /dev/null
+++ b/Firebase/Auth/Docs/threading.md
@@ -0,0 +1,119 @@
+# Firebase Auth Thread Safety
+
+This document describes how Firebase Auth maintains thread-safety. The Firebase
+Auth library (not including Firebase Auth UI and Auth Provider UIs for now)
+must be thread-safe, meaning deveopers are free to call any method in any
+thread at any time. Thus, all code that may take part in race conditions must
+be protected in some way.
+
+## Local Synchronization
+
+When contested data and accessing code is limited in scope, for example,
+a mutable array accessed only by two methods, a `@synchronized` directive is
+probably the simplest solution. Make sure the object to be locked on is not
+`nil`, e.g., `self`.
+
+## Global Work Queue
+
+A more scalable solution used throughout the current code base is to execute
+all potentially conflicting code in the same serial dispatch queue, which is
+referred as "the auth global work queue", or in some other serial queue that
+has its target queue set to this auth global work queue. This way we don't
+have to think about which variables may be contested. We only need to make
+sure all public APIs that may have thread-safety issues make the dispatch.
+The auth global work queue is defined in
+[FIRAuthGlobalWorkQueue.h](../Source/Private/FIRAuthGlobalWorkQueue.h)
+and any serial task queue created by
+[FIRAuthSerialTaskQueue.h](../Source/Private/FIRAuthSerialTaskQueue.h)
+already has its target set properly.
+
+In following sub-sections, we divided methods into three categories, according
+to the two criteria below:
+
+1. Whether the method is public or private:
+ * A public method can be directly called by developers.
+ * A private method can only be called by our own code.
+2. Whether the method is synchronous or asynchronous.
+ * A synchronous method returns some value or object in the calling
+ thread immediately.
+ * An asynchronous method returns nothing but calls the callback provided
+ by the caller at some point in future.
+
+### Public Asynchronous Methods
+
+Unless it's a simple wrapper of another public asynchronous method, a public
+asynchronous method shall
+
+* Dispatch asynchronously to the auth global work queue immediately.
+* Dispatch asynchronously to the main queue before calling the callback.
+ This is to make developers' life easier so they don't have to manage
+ thread-safety.
+
+The code would look like:
+
+```objectivec
+- (void)doSomethingWithCompletion:(nullable CompletionBlock)completion {
+ dispatch_async(FIRAuthGlobalWorkQueue(), ^{
+ // Do things...
+ if (completion) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ completion(args);
+ });
+ }
+ });
+}
+```
+
+### Public Synchronous Methods
+
+A public synchronous method that needs protection shall dispatch
+*synchronously* to the auth global work queue for its work. The code would
+look like:
+
+```objectivec
+- (ReturnType)something {
+ __block ReturnType result;
+ dispatch_sync(FIRAuthGlobalWorkQueue(), ^{
+ // Compute result.
+ result = computedResult;
+ });
+ return result;
+}
+```
+
+**But don't call methods protected this way from private methods, or a
+deadlock would occur.** This is because you are not supposed to
+`dispatch_sync` to the queue you're already in. This can be easily worked
+around by creating an equivalent private synchronous method to be called by
+both public and private methods and making the public synchronous method a
+wrapper of that. For example,
+
+```objectivec
+- (ReturnType)somethingInternal {
+ // Compute result.
+ return computedResult;
+}
+
+- (ReturnType)something {
+ __block ReturnType result;
+ dispatch_sync(FIRAuthGlobalWorkQueue(), ^{
+ result = [self somethingInternal];
+ });
+ return result;
+}
+```
+
+### Private Methods
+
+Generally speaking there is nothing special needed to be done for private
+methods:
+
+* The calling code should already be in the auth global work queue.
+* The callback, if any, is provided by our own code, so it expects to called
+ in the auth global work queue as well. This is usually already the case,
+ unless the method pass the callback to some other asychronous methods
+ outside our library, in which case we need to manually make the callback
+ called in the auth global work queue.
+
+Just beware you can't call public synchronous methods protected by the auth
+global work queue from private methods as stated in the preceding sub-section.
diff --git a/Firebase/Auth/FirebaseAuth.podspec b/Firebase/Auth/FirebaseAuth.podspec
new file mode 100644
index 0000000..74aa07c
--- /dev/null
+++ b/Firebase/Auth/FirebaseAuth.podspec
@@ -0,0 +1,56 @@
+# This podspec is not intended to be deployed. It is solely for the static
+# library framework build process at
+# https://github.com/firebase/firebase-ios-sdk/tree/master/BuildFrameworks
+
+Pod::Spec.new do |s|
+ s.name = 'FirebaseAuth'
+ s.version = '4.0.0'
+ s.summary = 'Firebase Open Source Libraries for iOS.'
+
+ s.description = <<-DESC
+Simplify your iOS development, grow your user base, and monetize more effectively with Firebase.
+ DESC
+
+ s.homepage = 'https://firebase.google.com'
+ s.license = { :type => 'Apache', :file => '../../LICENSE' }
+ s.authors = 'Google, Inc.'
+
+ # NOTE that the FirebaseDev pod is neither publicly deployed nor yet interchangeable with the
+ # Firebase pod
+ s.source = { :git => 'https://github.com/firebase/firebase-ios-sdk.git', :tag => s.version.to_s }
+ s.social_media_url = 'https://twitter.com/Firebase'
+ s.ios.deployment_target = '7.0'
+
+ s.source_files = '**/*.[mh]'
+ s.public_header_files =
+ 'Source/FirebaseAuth.h',
+ 'Source/FirebaseAuthVersion.h',
+ 'Source/FIRAdditionalUserInfo.h',
+ 'Source/FIRAuth.h',
+ 'Source/FIRAuthAPNSTokenType.h',
+ 'Source/FIRAuthCredential.h',
+ 'Source/FIRAuthDataResult.h',
+ 'Source/FIRAuthErrors.h',
+ 'Source/FIRAuthSwiftNameSupport.h',
+ 'Source/AuthProviders/EmailPassword/FIREmailAuthProvider.h',
+ 'Source/AuthProviders/Facebook/FIRFacebookAuthProvider.h',
+ 'Source/AuthProviders/GitHub/FIRGitHubAuthProvider.h',
+ 'Source/AuthProviders/Google/FIRGoogleAuthProvider.h',
+ 'Source/AuthProviders/OAuth/FIROAuthProvider.h',
+ 'Source/AuthProviders/Phone/FIRPhoneAuthCredential.h',
+ 'Source/AuthProviders/Phone/FIRPhoneAuthProvider.h',
+ 'Source/AuthProviders/Twitter/FIRTwitterAuthProvider.h',
+ 'Source/FIRUser.h',
+ 'Source/FIRUserInfo.h'
+ s.preserve_paths =
+ 'README.md',
+ 'CHANGELOG.md'
+ s.xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' =>
+ '$(inherited) ' + 'FIRAuth_VERSION=' + s.version.to_s +
+ ' FIRAuth_MINOR_VERSION=' + s.version.to_s.split(".")[0] + "." + s.version.to_s.split(".")[1]
+ }
+ s.framework = 'Security'
+# s.dependency 'FirebaseDev/Core'
+ s.dependency 'GTMSessionFetcher/Core', '~> 1.1'
+ s.dependency 'GoogleToolboxForMac/NSDictionary+URLArguments', '~> 2.1'
+end
diff --git a/Firebase/Auth/README.md b/Firebase/Auth/README.md
new file mode 100644
index 0000000..e766949
--- /dev/null
+++ b/Firebase/Auth/README.md
@@ -0,0 +1,8 @@
+# Firebase Auth for iOS
+
+Firebase Auth enables apps to easily support multiple authentication options
+for their end users.
+
+Please visit [our developer site](https://developers.google.com/) for
+integration instructions, documentation, support information, and terms of
+service.
diff --git a/Firebase/Auth/Source/AuthProviders/EmailPassword/FIREmailAuthProvider.h b/Firebase/Auth/Source/AuthProviders/EmailPassword/FIREmailAuthProvider.h
new file mode 100644
index 0000000..4fb5ea0
--- /dev/null
+++ b/Firebase/Auth/Source/AuthProviders/EmailPassword/FIREmailAuthProvider.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "FIRAuthSwiftNameSupport.h"
+
+@class FIRAuthCredential;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ @brief A string constant identifying the email & password identity provider.
+ */
+extern NSString *const FIREmailAuthProviderID FIR_SWIFT_NAME(EmailAuthProviderID);
+
+/**
+ @brief please use @c FIREmailAuthProviderID instead.
+ */
+extern NSString *const FIREmailPasswordAuthProviderID __attribute__((deprecated));
+
+/** @class FIREmailAuthProvider
+ @brief A concrete implementation of @c FIRAuthProvider for Email & Password Sign In.
+ */
+FIR_SWIFT_NAME(EmailAuthProvider)
+@interface FIREmailAuthProvider : NSObject
+
+/** @typedef FIREmailPasswordAuthProvider
+ @brief Please use @c FIREmailAuthProvider instead.
+ */
+typedef FIREmailAuthProvider FIREmailPasswordAuthProvider __attribute__((deprecated));
+
+
+/** @fn credentialWithEmail:password:
+ @brief Creates an @c FIRAuthCredential for an email & password sign in.
+
+ @param email The user's email address.
+ @param password The user's password.
+ @return A FIRAuthCredential containing the email & password credential.
+ */
++ (FIRAuthCredential *)credentialWithEmail:(NSString *)email password:(NSString *)password;
+
+/** @fn init
+ @brief This class is not meant to be initialized.
+ */
+- (instancetype)init NS_UNAVAILABLE;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/AuthProviders/EmailPassword/FIREmailAuthProvider.m b/Firebase/Auth/Source/AuthProviders/EmailPassword/FIREmailAuthProvider.m
new file mode 100644
index 0000000..d27611e
--- /dev/null
+++ b/Firebase/Auth/Source/AuthProviders/EmailPassword/FIREmailAuthProvider.m
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIREmailAuthProvider.h"
+
+#import "FIREmailPasswordAuthCredential.h"
+
+// FIREmailPasswordAuthProviderID is defined in FIRAuthProvider.m.
+
+@implementation FIREmailAuthProvider
+
+- (instancetype)init {
+ @throw [NSException exceptionWithName:@"Attempt to call unavailable initializer."
+ reason:@"This class is not meant to be initialized."
+ userInfo:nil];
+}
+
++ (FIRAuthCredential *)credentialWithEmail:(NSString *)email password:(NSString *)password {
+ return [[FIREmailPasswordAuthCredential alloc] initWithEmail:email password:password];
+}
+
+@end
diff --git a/Firebase/Auth/Source/AuthProviders/EmailPassword/FIREmailPasswordAuthCredential.h b/Firebase/Auth/Source/AuthProviders/EmailPassword/FIREmailPasswordAuthCredential.h
new file mode 100644
index 0000000..004716c
--- /dev/null
+++ b/Firebase/Auth/Source/AuthProviders/EmailPassword/FIREmailPasswordAuthCredential.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "../../Private/FIRAuthCredential_Internal.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @class FIREmailPasswordAuthCredential
+ @brief Internal implementation of FIRAuthCredential for Email/Password credentials.
+ */
+@interface FIREmailPasswordAuthCredential : FIRAuthCredential
+
+/** @property email
+ @brief The user's email address.
+ */
+@property(nonatomic, readonly) NSString *email;
+
+/** @property password
+ @brief The user's password.
+ */
+@property(nonatomic, readonly) NSString *password;
+
+/** @fn initWithEmail:password:
+ @brief Designated initializer.
+ @param email The user's email address.
+ @param password The user's password.
+ */
+- (nullable instancetype)initWithEmail:(NSString *)email password:(NSString *)password
+ NS_DESIGNATED_INITIALIZER;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/AuthProviders/EmailPassword/FIREmailPasswordAuthCredential.m b/Firebase/Auth/Source/AuthProviders/EmailPassword/FIREmailPasswordAuthCredential.m
new file mode 100644
index 0000000..4361366
--- /dev/null
+++ b/Firebase/Auth/Source/AuthProviders/EmailPassword/FIREmailPasswordAuthCredential.m
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIREmailPasswordAuthCredential.h"
+
+#import "FIREmailAuthProvider.h"
+#import "FIRAuthExceptionUtils.h"
+#import "FIRVerifyAssertionRequest.h"
+
+@interface FIREmailPasswordAuthCredential ()
+
+- (nullable instancetype)initWithProvider:(NSString *)provider NS_UNAVAILABLE;
+
+@end
+
+@implementation FIREmailPasswordAuthCredential
+
+- (nullable instancetype)initWithProvider:(NSString *)provider {
+ [FIRAuthExceptionUtils raiseMethodNotImplementedExceptionWithReason:
+ @"Please call the designated initializer."];
+ return nil;
+}
+
+- (nullable instancetype)initWithEmail:(NSString *)email password:(NSString *)password {
+ self = [super initWithProvider:FIREmailAuthProviderID];
+ if (self) {
+ _email = [email copy];
+ _password = [password copy];
+ }
+ return self;
+}
+
+- (void)prepareVerifyAssertionRequest:(FIRVerifyAssertionRequest *)request {
+ [FIRAuthExceptionUtils raiseMethodNotImplementedExceptionWithReason:
+ @"Attempt to call prepareVerifyAssertionRequest: on a FIREmailPasswordAuthCredential."];
+}
+
+@end
diff --git a/Firebase/Auth/Source/AuthProviders/EmailPassword/FIREmailPasswordAuthProvider.h b/Firebase/Auth/Source/AuthProviders/EmailPassword/FIREmailPasswordAuthProvider.h
new file mode 100644
index 0000000..bf7db21
--- /dev/null
+++ b/Firebase/Auth/Source/AuthProviders/EmailPassword/FIREmailPasswordAuthProvider.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+@class FIRAuthCredential;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ @brief A string constant identifying the email & password identity provider.
+ */
+extern NSString *const FIREmailPasswordAuthProviderID;
+
+/** @class FIREmailPasswordAuthProvider
+ @brief A concrete implementation of @c FIRAuthProvider for Email & Password Sign In.
+ */
+@interface FIREmailPasswordAuthProvider : NSObject
+
+/** @fn credentialWithEmail:password:
+ @brief Creates an @c FIRAuthCredential for an email & password sign in.
+
+ @param email The user's email address.
+ @param password The user's password.
+ @return A FIRAuthCredential containing the email & password credential.
+ */
++ (FIRAuthCredential *)credentialWithEmail:(NSString *)email password:(NSString *)password;
+
+/** @fn init
+ @brief This class is not meant to be initialized.
+ */
+- (instancetype)init NS_UNAVAILABLE;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/AuthProviders/EmailPassword/FIREmailPasswordAuthProvider.m b/Firebase/Auth/Source/AuthProviders/EmailPassword/FIREmailPasswordAuthProvider.m
new file mode 100644
index 0000000..84c3787
--- /dev/null
+++ b/Firebase/Auth/Source/AuthProviders/EmailPassword/FIREmailPasswordAuthProvider.m
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIREmailPasswordAuthProvider.h"
+
+#import "FIREmailPasswordAuthCredential.h"
+
+// FIREmailPasswordAuthProviderID is defined in FIRAuthProvider.m.
+
+@implementation FIREmailPasswordAuthProvider
+
+- (instancetype)init {
+ @throw [NSException exceptionWithName:@"Attempt to call unavailable initializer."
+ reason:@"This class is not meant to be initialized."
+ userInfo:nil];
+}
+
++ (FIRAuthCredential *)credentialWithEmail:(NSString *)email password:(NSString *)password {
+ return [[FIREmailPasswordAuthCredential alloc] initWithEmail:email password:password];
+}
+
+@end
diff --git a/Firebase/Auth/Source/AuthProviders/Facebook/FIRFacebookAuthCredential.h b/Firebase/Auth/Source/AuthProviders/Facebook/FIRFacebookAuthCredential.h
new file mode 100644
index 0000000..1c03573
--- /dev/null
+++ b/Firebase/Auth/Source/AuthProviders/Facebook/FIRFacebookAuthCredential.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "../../Private/FIRAuthCredential_Internal.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @class FIRFacebookAuthCredential
+ @brief Internal implementation of FIRAuthCredential for the Facebook IdP.
+ */
+@interface FIRFacebookAuthCredential : FIRAuthCredential
+
+/** @fn initWithAccessToken:
+ @brief Designated initializer.
+ @param accessToken The Access Token obtained from Facebook.
+ */
+- (nullable instancetype)initWithAccessToken:(NSString *)accessToken NS_DESIGNATED_INITIALIZER;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/AuthProviders/Facebook/FIRFacebookAuthCredential.m b/Firebase/Auth/Source/AuthProviders/Facebook/FIRFacebookAuthCredential.m
new file mode 100644
index 0000000..1c3576a
--- /dev/null
+++ b/Firebase/Auth/Source/AuthProviders/Facebook/FIRFacebookAuthCredential.m
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRFacebookAuthCredential.h"
+
+#import "FIRFacebookAuthProvider.h"
+#import "FIRAuthExceptionUtils.h"
+#import "FIRVerifyAssertionRequest.h"
+
+@interface FIRFacebookAuthCredential ()
+
+- (nullable instancetype)initWithProvider:(NSString *)provider NS_UNAVAILABLE;
+
+@end
+
+@implementation FIRFacebookAuthCredential {
+ NSString *_accessToken;
+}
+
+- (nullable instancetype)initWithProvider:(NSString *)provider {
+ [FIRAuthExceptionUtils raiseMethodNotImplementedExceptionWithReason:
+ @"Please call the designated initializer."];
+ return nil;
+}
+
+- (nullable instancetype)initWithAccessToken:(NSString *)accessToken {
+ self = [super initWithProvider:FIRFacebookAuthProviderID];
+ if (self) {
+ _accessToken = [accessToken copy];
+ }
+ return self;
+}
+
+- (void)prepareVerifyAssertionRequest:(FIRVerifyAssertionRequest *)request {
+ request.providerAccessToken = _accessToken;
+}
+
+@end
diff --git a/Firebase/Auth/Source/AuthProviders/Facebook/FIRFacebookAuthProvider.h b/Firebase/Auth/Source/AuthProviders/Facebook/FIRFacebookAuthProvider.h
new file mode 100644
index 0000000..2307b08
--- /dev/null
+++ b/Firebase/Auth/Source/AuthProviders/Facebook/FIRFacebookAuthProvider.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "FIRAuthSwiftNameSupport.h"
+
+@class FIRAuthCredential;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ @brief A string constant identifying the Facebook identity provider.
+ */
+extern NSString *const FIRFacebookAuthProviderID FIR_SWIFT_NAME(FacebookAuthProviderID);
+
+/** @class FIRFacebookAuthProvider
+ @brief Utility class for constructing Facebook credentials.
+ */
+FIR_SWIFT_NAME(FacebookAuthProvider)
+@interface FIRFacebookAuthProvider : NSObject
+
+/** @fn credentialWithAccessToken:
+ @brief Creates an @c FIRAuthCredential for a Facebook sign in.
+
+ @param accessToken The Access Token from Facebook.
+ @return A FIRAuthCredential containing the Facebook credentials.
+ */
++ (FIRAuthCredential *)credentialWithAccessToken:(NSString *)accessToken;
+
+/** @fn init
+ @brief This class should not be initialized.
+ */
+- (instancetype)init NS_UNAVAILABLE;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/AuthProviders/Facebook/FIRFacebookAuthProvider.m b/Firebase/Auth/Source/AuthProviders/Facebook/FIRFacebookAuthProvider.m
new file mode 100644
index 0000000..d2759ae
--- /dev/null
+++ b/Firebase/Auth/Source/AuthProviders/Facebook/FIRFacebookAuthProvider.m
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRFacebookAuthProvider.h"
+
+#import "FIRFacebookAuthCredential.h"
+#import "FIRAuthExceptionUtils.h"
+
+// FIRFacebookAuthProviderID is defined in FIRAuthProvider.m.
+
+@implementation FIRFacebookAuthProvider
+
+- (instancetype)init {
+ [FIRAuthExceptionUtils raiseMethodNotImplementedExceptionWithReason:
+ @"This class is not meant to be initialized."];
+ return nil;
+}
+
++ (FIRAuthCredential *)credentialWithAccessToken:(NSString *)accessToken {
+ return [[FIRFacebookAuthCredential alloc] initWithAccessToken:accessToken];
+}
+
+@end
diff --git a/Firebase/Auth/Source/AuthProviders/GitHub/FIRGitHubAuthCredential.h b/Firebase/Auth/Source/AuthProviders/GitHub/FIRGitHubAuthCredential.h
new file mode 100644
index 0000000..c43fb52
--- /dev/null
+++ b/Firebase/Auth/Source/AuthProviders/GitHub/FIRGitHubAuthCredential.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "../../Private/FIRAuthCredential_Internal.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @class FIRGitHubAuthCredential
+ @brief Internal implementation of FIRAuthCredential for GitHub credentials.
+ */
+@interface FIRGitHubAuthCredential : FIRAuthCredential
+
+/** @property token
+ @brief The GitHub OAuth access token.
+ */
+@property(nonatomic, readonly) NSString *token;
+
+/** @fn initWithToken:
+ @brief Designated initializer.
+ @param token The GitHub OAuth access token.
+ */
+- (nullable instancetype)initWithToken:(NSString *)token NS_DESIGNATED_INITIALIZER;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/AuthProviders/GitHub/FIRGitHubAuthCredential.m b/Firebase/Auth/Source/AuthProviders/GitHub/FIRGitHubAuthCredential.m
new file mode 100644
index 0000000..a0185eb
--- /dev/null
+++ b/Firebase/Auth/Source/AuthProviders/GitHub/FIRGitHubAuthCredential.m
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRGitHubAuthCredential.h"
+
+#import "FIRGitHubAuthProvider.h"
+#import "FIRAuthExceptionUtils.h"
+#import "FIRVerifyAssertionRequest.h"
+
+@interface FIRGitHubAuthCredential ()
+
+- (nullable instancetype)initWithProvider:(NSString *)provider NS_UNAVAILABLE;
+
+@end
+
+@implementation FIRGitHubAuthCredential
+
+- (nullable instancetype)initWithProvider:(NSString *)provider {
+ [FIRAuthExceptionUtils raiseMethodNotImplementedExceptionWithReason:
+ @"Please call the designated initializer."];
+ return nil;
+}
+
+- (nullable instancetype)initWithToken:(NSString *)token {
+ self = [super initWithProvider:FIRGitHubAuthProviderID];
+ if (self) {
+ _token = [token copy];
+ }
+ return self;
+}
+
+- (void)prepareVerifyAssertionRequest:(FIRVerifyAssertionRequest *)request {
+ request.providerAccessToken = _token;
+}
+
+@end
diff --git a/Firebase/Auth/Source/AuthProviders/GitHub/FIRGitHubAuthProvider.h b/Firebase/Auth/Source/AuthProviders/GitHub/FIRGitHubAuthProvider.h
new file mode 100644
index 0000000..ab5c0ef
--- /dev/null
+++ b/Firebase/Auth/Source/AuthProviders/GitHub/FIRGitHubAuthProvider.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "FIRAuthSwiftNameSupport.h"
+
+@class FIRAuthCredential;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ @brief A string constant identifying the GitHub identity provider.
+ */
+extern NSString *const FIRGitHubAuthProviderID FIR_SWIFT_NAME(GitHubAuthProviderID);
+
+/** @class FIRGitHubAuthProvider
+ @brief Utility class for constructing GitHub credentials.
+ */
+FIR_SWIFT_NAME(GitHubAuthProvider)
+@interface FIRGitHubAuthProvider : NSObject
+
+/** @fn credentialWithToken:
+ @brief Creates an @c FIRAuthCredential for a GitHub sign in.
+
+ @param token The GitHub OAuth access token.
+ @return A FIRAuthCredential containing the GitHub credential.
+ */
++ (FIRAuthCredential *)credentialWithToken:(NSString *)token;
+
+/** @fn init
+ @brief This class is not meant to be initialized.
+ */
+- (instancetype)init NS_UNAVAILABLE;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/AuthProviders/GitHub/FIRGitHubAuthProvider.m b/Firebase/Auth/Source/AuthProviders/GitHub/FIRGitHubAuthProvider.m
new file mode 100644
index 0000000..8e0ff76
--- /dev/null
+++ b/Firebase/Auth/Source/AuthProviders/GitHub/FIRGitHubAuthProvider.m
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRGitHubAuthProvider.h"
+
+#import "FIRGitHubAuthCredential.h"
+#import "FIRAuthExceptionUtils.h"
+
+// FIRGitHubAuthProviderID is defined in FIRAuthProvider.m.
+
+@implementation FIRGitHubAuthProvider
+
+- (instancetype)init {
+ [FIRAuthExceptionUtils raiseMethodNotImplementedExceptionWithReason:
+ @"This class is not meant to be initialized."];
+ return nil;
+}
+
++ (FIRAuthCredential *)credentialWithToken:(NSString *)token {
+ return [[FIRGitHubAuthCredential alloc] initWithToken:token];
+}
+
+@end
diff --git a/Firebase/Auth/Source/AuthProviders/Google/FIRGoogleAuthCredential.h b/Firebase/Auth/Source/AuthProviders/Google/FIRGoogleAuthCredential.h
new file mode 100644
index 0000000..ae98fbc
--- /dev/null
+++ b/Firebase/Auth/Source/AuthProviders/Google/FIRGoogleAuthCredential.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "../../Private/FIRAuthCredential_Internal.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @class FIRGoogleAuthCredential
+ @brief Internal implementation of FIRAuthCredential for the Google IdP.
+ */
+@interface FIRGoogleAuthCredential : FIRAuthCredential
+
+/** @fn initWithIDToken:accessToken:
+ @brief Designated initializer.
+ @param IDToken The ID Token obtained from Google.
+ @param accessToken The Access Token obtained from Google.
+ */
+- (nullable instancetype)initWithIDToken:(NSString *)IDToken accessToken:(NSString *)accessToken
+ NS_DESIGNATED_INITIALIZER;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/AuthProviders/Google/FIRGoogleAuthCredential.m b/Firebase/Auth/Source/AuthProviders/Google/FIRGoogleAuthCredential.m
new file mode 100644
index 0000000..d66b2e2
--- /dev/null
+++ b/Firebase/Auth/Source/AuthProviders/Google/FIRGoogleAuthCredential.m
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRGoogleAuthCredential.h"
+
+#import "FIRGoogleAuthProvider.h"
+#import "FIRAuthExceptionUtils.h"
+#import "FIRVerifyAssertionRequest.h"
+
+@interface FIRGoogleAuthCredential ()
+
+- (nullable instancetype)initWithProvider:(NSString *)provider NS_UNAVAILABLE;
+
+@end
+
+@implementation FIRGoogleAuthCredential {
+ NSString *_IDToken;
+ NSString *_accessToken;
+}
+
+- (nullable instancetype)initWithProvider:(NSString *)provider {
+ [FIRAuthExceptionUtils raiseMethodNotImplementedExceptionWithReason:
+ @"Please call the designated initializer."];
+ return nil;
+}
+
+- (nullable instancetype)initWithIDToken:(NSString *)IDToken accessToken:(NSString *)accessToken {
+ self = [super initWithProvider:FIRGoogleAuthProviderID];
+ if (self) {
+ _IDToken = [IDToken copy];
+ _accessToken = [accessToken copy];
+ }
+ return self;
+}
+
+- (void)prepareVerifyAssertionRequest:(FIRVerifyAssertionRequest *)request {
+ request.providerIDToken = _IDToken;
+ request.providerAccessToken = _accessToken;
+}
+
+@end
diff --git a/Firebase/Auth/Source/AuthProviders/Google/FIRGoogleAuthProvider.h b/Firebase/Auth/Source/AuthProviders/Google/FIRGoogleAuthProvider.h
new file mode 100644
index 0000000..92f0db2
--- /dev/null
+++ b/Firebase/Auth/Source/AuthProviders/Google/FIRGoogleAuthProvider.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "FIRAuthSwiftNameSupport.h"
+
+@class FIRAuthCredential;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ @brief A string constant identifying the Google identity provider.
+ */
+extern NSString *const FIRGoogleAuthProviderID FIR_SWIFT_NAME(GoogleAuthProviderID);
+
+/** @class FIRGoogleAuthProvider
+ @brief Utility class for constructing Google Sign In credentials.
+ */
+FIR_SWIFT_NAME(GoogleAuthProvider)
+@interface FIRGoogleAuthProvider : NSObject
+
+/** @fn credentialWithIDToken:accessToken:
+ @brief Creates an @c FIRAuthCredential for a Google sign in.
+
+ @param IDToken The ID Token from Google.
+ @param accessToken The Access Token from Google.
+ @return A FIRAuthCredential containing the Google credentials.
+ */
++ (FIRAuthCredential *)credentialWithIDToken:(NSString *)IDToken
+ accessToken:(NSString *)accessToken;
+
+/** @fn init
+ @brief This class should not be initialized.
+ */
+- (instancetype)init NS_UNAVAILABLE;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/AuthProviders/Google/FIRGoogleAuthProvider.m b/Firebase/Auth/Source/AuthProviders/Google/FIRGoogleAuthProvider.m
new file mode 100644
index 0000000..a2f4c79
--- /dev/null
+++ b/Firebase/Auth/Source/AuthProviders/Google/FIRGoogleAuthProvider.m
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRGoogleAuthProvider.h"
+
+#import "FIRGoogleAuthCredential.h"
+#import "FIRAuthExceptionUtils.h"
+
+// FIRGoogleAuthProviderID is defined in FIRAuthProvider.m.
+
+@implementation FIRGoogleAuthProvider
+
+- (instancetype)init {
+ [FIRAuthExceptionUtils raiseMethodNotImplementedExceptionWithReason:
+ @"This class is not meant to be initialized."];
+ return nil;
+}
+
++ (FIRAuthCredential *)credentialWithIDToken:(NSString *)IDToken
+ accessToken:(NSString *)accessToken {
+ return [[FIRGoogleAuthCredential alloc] initWithIDToken:IDToken accessToken:accessToken];
+}
+
+@end
diff --git a/Firebase/Auth/Source/AuthProviders/OAuth/FIROAuthCredential.h b/Firebase/Auth/Source/AuthProviders/OAuth/FIROAuthCredential.h
new file mode 100644
index 0000000..744df33
--- /dev/null
+++ b/Firebase/Auth/Source/AuthProviders/OAuth/FIROAuthCredential.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "../../Private/FIRAuthCredential_Internal.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @class FIROAuthCredential
+ @brief Internal implementation of FIRAuthCredential for generic credentials.
+ */
+@interface FIROAuthCredential : FIRAuthCredential
+
+/** @property providerID
+ @brief The provider ID associated with this credential.
+ */
+@property(nonatomic, readonly) NSString *providerID;
+
+/** @property IDToken
+ @brief The ID Token associated with this credential.
+ */
+@property(nonatomic, readonly) NSString *IDToken;
+
+/** @property accessToken
+ @brief The access token associated with this credential.
+ */
+@property(nonatomic, readonly) NSString *accessToken;
+
+/** @fn initWithProviderId:IDToken:accessToken:
+ @brief Designated initializer.
+ @param providerID The provider ID associated with the credential being created.
+ @param IDToken The ID Token associated with the credential being created.
+ @param accessToken The access token associated with the credential being created.
+ */
+- (nullable instancetype)initWithProvierID:(NSString *)providerID
+ IDToken:(nullable NSString*)IDToken
+ accessToken:(nullable NSString *)accessToken;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/AuthProviders/OAuth/FIROAuthCredential.m b/Firebase/Auth/Source/AuthProviders/OAuth/FIROAuthCredential.m
new file mode 100644
index 0000000..28712a6
--- /dev/null
+++ b/Firebase/Auth/Source/AuthProviders/OAuth/FIROAuthCredential.m
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIROAuthCredential.h"
+#import "FIRAuthExceptionUtils.h"
+#import "FIRVerifyAssertionRequest.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface FIROAuthCredential ()
+
+- (nullable instancetype)initWithProvider:(NSString *)provider NS_UNAVAILABLE;
+
+@end
+
+@implementation FIROAuthCredential
+
+- (nullable instancetype)initWithProvierID:(NSString *)providerID
+ IDToken:(nullable NSString *)IDToken
+ accessToken:(nullable NSString *)accessToken {
+ self = [super initWithProvider:providerID];
+ if (self) {
+ _providerID = providerID;
+ _IDToken = IDToken;
+ _accessToken = accessToken;
+ }
+ return self;
+}
+
+- (void)prepareVerifyAssertionRequest:(FIRVerifyAssertionRequest *)request {
+ request.providerIDToken = _IDToken;
+ request.providerAccessToken = _accessToken;
+}
+
+NS_ASSUME_NONNULL_END
+
+@end
diff --git a/Firebase/Auth/Source/AuthProviders/OAuth/FIROAuthProvider.h b/Firebase/Auth/Source/AuthProviders/OAuth/FIROAuthProvider.h
new file mode 100644
index 0000000..e059b22
--- /dev/null
+++ b/Firebase/Auth/Source/AuthProviders/OAuth/FIROAuthProvider.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "FIRAuthSwiftNameSupport.h"
+
+@class FIRAuthCredential;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @class FIROAuthProvider
+ @brief A concrete implementation of @c FIRAuthProvider for generic OAuth Providers.
+ */
+FIR_SWIFT_NAME(OAuthProvider)
+@interface FIROAuthProvider : NSObject
+
+/** @fn credentialWithProviderID:IDToken:accessToken:
+ @brief Creates an @c FIRAuthCredential for that OAuth 2 provider identified by providerID, ID
+ token and access token.
+
+ @param providerID The provider ID associated with the Auth credential being created.
+ @param IDToken The IDToken associated with the Auth credential being created.
+ @param accessToken The accessstoken associated with the Auth credential be created, if
+ available.
+ @return A FIRAuthCredential for the specified provider ID, ID token and access token.
+ */
++ (FIRAuthCredential *)credentialWithProviderID:(NSString *)providerID
+ IDToken:(NSString *)IDToken
+ accessToken:(nullable NSString *)accessToken;
+
+
+/** @fn credentialWithProviderID:accessToken:
+ @brief Creates an @c FIRAuthCredential for that OAuth 2 provider identified by providerID using
+ an ID token.
+
+ @param providerID The provider ID associated with the Auth credential being created.
+ @param accessToken The accessstoken associated with the Auth credential be created
+ @return A FIRAuthCredential.
+ */
++ (FIRAuthCredential *)credentialWithProviderID:(NSString *)providerID
+ accessToken:(NSString *)accessToken;
+
+/** @fn init
+ @brief This class is not meant to be initialized.
+ */
+- (instancetype)init NS_UNAVAILABLE;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/AuthProviders/OAuth/FIROAuthProvider.m b/Firebase/Auth/Source/AuthProviders/OAuth/FIROAuthProvider.m
new file mode 100644
index 0000000..e810680
--- /dev/null
+++ b/Firebase/Auth/Source/AuthProviders/OAuth/FIROAuthProvider.m
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIROAuthProvider.h"
+
+#import "FIROAuthCredential.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@implementation FIROAuthProvider
+
++ (FIRAuthCredential *)credentialWithProviderID:(NSString *)providerID
+ IDToken:(NSString *)IDToken
+ accessToken:(nullable NSString *)accessToken {
+ return [[FIROAuthCredential alloc] initWithProvierID:providerID
+ IDToken:IDToken
+ accessToken:accessToken];
+}
+
++ (FIROAuthCredential *)credentialWithProviderID:(NSString *)providerID
+ accessToken:(NSString *)accessToken {
+ return [[FIROAuthCredential alloc] initWithProvierID:providerID
+ IDToken:nil
+ accessToken:accessToken];
+}
+
+NS_ASSUME_NONNULL_END
+
+@end
diff --git a/Firebase/Auth/Source/AuthProviders/Phone/FIRPhoneAuthCredential.h b/Firebase/Auth/Source/AuthProviders/Phone/FIRPhoneAuthCredential.h
new file mode 100644
index 0000000..d951564
--- /dev/null
+++ b/Firebase/Auth/Source/AuthProviders/Phone/FIRPhoneAuthCredential.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "FIRAuthCredential.h"
+#import "FIRAuthSwiftNameSupport.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @class FIRPhoneAuthCredential
+ @brief Implementation of FIRAuthCredential for Phone Auth credentials.
+ */
+FIR_SWIFT_NAME(PhoneAuthCredential)
+@interface FIRPhoneAuthCredential : FIRAuthCredential
+
+/** @fn init
+ @brief This class is not supposed to be instantiated directly.
+ */
+- (instancetype)init NS_UNAVAILABLE;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/AuthProviders/Phone/FIRPhoneAuthCredential.m b/Firebase/Auth/Source/AuthProviders/Phone/FIRPhoneAuthCredential.m
new file mode 100644
index 0000000..b9bf577
--- /dev/null
+++ b/Firebase/Auth/Source/AuthProviders/Phone/FIRPhoneAuthCredential.m
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRPhoneAuthCredential.h"
+
+#import "FIRPhoneAuthProvider.h"
+#import "FIRPhoneAuthCredential_Internal.h"
+#import "FIRAuthCredential_Internal.h"
+#import "FIRAuthExceptionUtils.h"
+#import "FIRVerifyAssertionRequest.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface FIRPhoneAuthCredential ()
+
+- (nullable instancetype)initWithProvider:(NSString *)provider NS_UNAVAILABLE;
+
+@end
+
+@implementation FIRPhoneAuthCredential
+
+- (instancetype)initWithTemporaryProof:(NSString *)temporaryProof
+ phoneNumber:(NSString *)phoneNumber
+ providerID:(NSString *)providerID {
+ self = [super initWithProvider:providerID];
+ if (self) {
+ _temporaryProof = [temporaryProof copy];
+ _phoneNumber = [phoneNumber copy];
+ }
+ return self;
+}
+
+- (nullable instancetype)initWithProvider:(NSString *)provider {
+ [FIRAuthExceptionUtils raiseMethodNotImplementedExceptionWithReason:
+ @"Please call the designated initializer."];
+ return nil;
+}
+
+- (instancetype)initWithProviderID:(NSString *)providerID
+ verificationID:(NSString *)verificationID
+ verificationCode:(NSString *)verificationCode {
+ self = [super initWithProvider:providerID];
+ if (self) {
+ _verificationID = [verificationID copy];
+ _verificationCode = [verificationCode copy];
+ }
+ return self;
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/AuthProviders/Phone/FIRPhoneAuthCredential_Internal.h b/Firebase/Auth/Source/AuthProviders/Phone/FIRPhoneAuthCredential_Internal.h
new file mode 100644
index 0000000..f260b89
--- /dev/null
+++ b/Firebase/Auth/Source/AuthProviders/Phone/FIRPhoneAuthCredential_Internal.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#import <Foundation/Foundation.h>
+
+#import "FIRPhoneAuthCredential.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @extension FIRPhoneAuthCredential
+ @brief Internal implementation of FIRAuthCredential for Phone Auth credentials.
+ */
+@interface FIRPhoneAuthCredential ()
+
+/** @var verificationID
+ @brief The verification ID obtained from invoking @c verifyPhoneNumber:completion:
+ */
+@property(nonatomic, readonly, nonnull) NSString *verificationID;
+
+/** @var verificationCode
+ @brief The verification code provided by the user.
+ */
+@property(nonatomic, readonly, nonnull) NSString *verificationCode;
+
+/** @var temporaryProof
+ @brief The a temporary proof code perftaining to this credential, returned from the backend.
+ */
+@property(nonatomic, readonly, nonnull) NSString *temporaryProof;
+
+/** @var phoneNumber
+ @brief The a phone number pertaining to this credential, returned from the backend.
+ */
+@property(nonatomic, readonly, nonnull) NSString *phoneNumber;
+
+/** @var initWithTemporaryProof:phoneNumber:
+ @brief Designated Initializer.
+ @param providerID The provider ID associated with the phone auth credential being created.
+ */
+- (instancetype)initWithTemporaryProof:(NSString *)temporaryProof
+ phoneNumber:(NSString *)phoneNumber
+ providerID:(NSString *)providerID NS_DESIGNATED_INITIALIZER;
+
+/** @var initWithProviderID:verificationID:verificationCode:
+ @brief Designated Initializer.
+ @param providerID The provider ID associated with the phone auth credential being created.
+ @param verificationID The verification ID associated witht Phone Auth credential being created.
+ @param verificationCode The verification code associated witht Phone Auth credential being
+ created.
+ */
+- (instancetype)initWithProviderID:(NSString *)providerID
+ verificationID:(NSString *)verificationID
+ verificationCode:(NSString *)verificationCode NS_DESIGNATED_INITIALIZER;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/AuthProviders/Phone/FIRPhoneAuthProvider.h b/Firebase/Auth/Source/AuthProviders/Phone/FIRPhoneAuthProvider.h
new file mode 100644
index 0000000..bc12b43
--- /dev/null
+++ b/Firebase/Auth/Source/AuthProviders/Phone/FIRPhoneAuthProvider.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "FIRAuth.h"
+#import "FIRAuthSwiftNameSupport.h"
+
+@class FIRPhoneAuthCredential;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @var FIRPhoneAuthProviderID
+ @brief A string constant identifying the phone identity provider.
+ */
+extern NSString *const FIRPhoneAuthProviderID FIR_SWIFT_NAME(PhoneAuthProviderID);
+
+/** @typedef FIRVerificationResultCallback
+ @brief The type of block invoked when a request to send a verification code has finished.
+
+ @param verificationID On success, the verification ID provided, nil otherwise.
+ @param error On error, the error that occured, nil otherwise.
+ */
+typedef void (^FIRVerificationResultCallback)(NSString *_Nullable verificationID,
+ NSError *_Nullable error)
+ FIR_SWIFT_NAME(VerificationResultCallback);
+
+/** @class FIRPhoneNumberProvider
+ @brief A concrete implementation of @c FIRAuthProvider for Phone Auth Providers.
+ */
+FIR_SWIFT_NAME(PhoneAuthProvider)
+@interface FIRPhoneAuthProvider : NSObject
+
+/** @fn provider
+ @brief Returns an instance of @c FIRPhoneAuthProvider for the default @c FIRAuth object.
+ */
++ (instancetype)provider FIR_SWIFT_NAME(provider());
+
+/** @fn providerWithAuth:
+ @brief Returns an instance of @c FIRPhoneAuthProvider for the provided @c FIRAuth object.
+
+ @param auth The auth object to associate with the @c PhoneauthProvider instance.
+ */
++ (instancetype)providerWithAuth:(FIRAuth *)auth FIR_SWIFT_NAME(provider(auth:));
+
+/** @fn verifyPhoneNumber:completion:
+ @brief Starts the phone number authentication flow by sending a verifcation code to the
+ specified phone number.
+
+ @param phoneNumber The phone number to be verified.
+ @param completion The callback to be invoked when the verification flow is finished.
+ */
+- (void)verifyPhoneNumber:(NSString *)phoneNumber
+ completion:(nullable FIRVerificationResultCallback)completion;
+
+/** @fn credentialWithVerificationID:verificationCode:
+ @brief Creates an @c FIRAuthCredential for the phone number provider identified by the
+ verification ID and verification code.
+
+ @param verificationID The verification ID obtained from invoking @c
+ verifyPhoneNumber:completion:
+ @param verificationCode The verification code obtained from the user.
+ @return The corresponding @c FIRAuthCredential for the verification ID and verification code
+ provided.
+ */
+- (FIRPhoneAuthCredential *)credentialWithVerificationID:(NSString *)verificationID
+ verificationCode:(NSString *)verificationCode;
+
+/** @fn init
+ @brief Please use the @c provider or @providerWithAuth: methods to obtain an instance of @c
+ FIRPhoneAuthProvider.
+ */
+- (instancetype)init NS_UNAVAILABLE;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/AuthProviders/Phone/FIRPhoneAuthProvider.m b/Firebase/Auth/Source/AuthProviders/Phone/FIRPhoneAuthProvider.m
new file mode 100644
index 0000000..423b2b6
--- /dev/null
+++ b/Firebase/Auth/Source/AuthProviders/Phone/FIRPhoneAuthProvider.m
@@ -0,0 +1,213 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRPhoneAuthProvider.h"
+
+#import "FIRLogger.h"
+#import "FIRPhoneAuthCredential_Internal.h"
+#import "NSString+FIRAuth.h"
+#import "../../Private/FIRAuthAPNSToken.h"
+#import "../../Private/FIRAuthAPNSTokenManager.h"
+#import "../../Private/FIRAuthAppCredential.h"
+#import "../../Private/FIRAuthAppCredentialManager.h"
+#import "../../Private/FIRAuthGlobalWorkQueue.h"
+#import "../../Private/FIRAuth_Internal.h"
+#import "../../Private/FIRAuthNotificationManager.h"
+#import "../../Private/FIRAuthErrorUtils.h"
+#import "FIRAuthBackend.h"
+#import "FIRSendVerificationCodeRequest.h"
+#import "FIRSendVerificationCodeResponse.h"
+#import "FIRVerifyClientRequest.h"
+#import "FIRVerifyClientResponse.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @typedef FIRVerifyClientCallback
+ @brief The callback invoked at the end of a client verification flow.
+ @param appCredential credential that proves the identity of the app during a phone
+ authentication flow.
+ @param error The error that occured while verifying the app, if any.
+ */
+typedef void (^FIRVerifyClientCallback)(FIRAuthAppCredential *_Nullable appCredential,
+ NSError *_Nullable error);
+
+@implementation FIRPhoneAuthProvider {
+
+ /** @var _auth
+ @brief The auth instance used to for verifying the phone number.
+ */
+ FIRAuth *_auth;
+}
+
+/** @fn initWithAuth:
+ @brief returns an instance of @c FIRPhoneAuthProvider assocaited with the provided auth
+ instance.
+ @return An Instance of @c FIRPhoneAuthProvider.
+ */
+- (nullable instancetype)initWithAuth:(FIRAuth *)auth {
+ self = [super init];
+ if (self) {
+ _auth = auth;
+ }
+ return self;
+}
+
+- (void)verifyPhoneNumber:(NSString *)phoneNumber
+ completion:(nullable FIRVerificationResultCallback)completion {
+ dispatch_async(FIRAuthGlobalWorkQueue(), ^{
+ FIRVerificationResultCallback callBackOnMainThread = ^(NSString *_Nullable verificationID,
+ NSError *_Nullable error) {
+ if (completion) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ completion(verificationID, error);
+ });
+ }
+ };
+
+ if (!phoneNumber.length) {
+ callBackOnMainThread(nil,
+ [FIRAuthErrorUtils missingPhoneNumberErrorWithMessage:nil]);
+ return;
+ }
+ [_auth.notificationManager checkNotificationForwardingWithCallback:
+ ^(BOOL isNotificationBeingForwarded) {
+ if (!isNotificationBeingForwarded) {
+ callBackOnMainThread(nil, [FIRAuthErrorUtils notificationNotForwardedError]);
+ return;
+ }
+ [self verifyClientAndSendVerificationCodeToPhoneNumber:phoneNumber
+ retryOnInvalidAppCredential:YES
+ callback:callBackOnMainThread];
+ }];
+ });
+}
+
+- (FIRPhoneAuthCredential *)credentialWithVerificationID:(NSString *)verificationID
+ verificationCode:(NSString *)verificationCode {
+ return [[FIRPhoneAuthCredential alloc] initWithProviderID:FIRPhoneAuthProviderID
+ verificationID:verificationID
+ verificationCode:verificationCode];
+}
+
++ (instancetype)provider {
+ return [[self alloc]initWithAuth:[FIRAuth auth]];
+}
+
++ (instancetype)providerWithAuth:(FIRAuth *)auth {
+ return [[self alloc]initWithAuth:auth];
+}
+
+#pragma mark - Internal Methods
+
+/** @fn verifyClientAndSendVerificationCodeToPhoneNumber:retryOnInvalidAppCredential:callback:
+ @brief Starts the flow to verify the client via silent push notification.
+ @param retryOnInvalidAppCredential Whether of not the flow should be retried if an
+ FIRAuthErrorCodeInvalidAppCredential error is returned from the backend.
+ @param phoneNumber The phone number to be verified.
+ @param callback The callback to be invoked on the global work queue when the flow is
+ finished.
+ */
+- (void)verifyClientAndSendVerificationCodeToPhoneNumber:(NSString *)phoneNumber
+ retryOnInvalidAppCredential:(BOOL)retryOnInvalidAppCredential
+ callback:(FIRVerificationResultCallback)callback {
+ [self verifyClientWithCompletion:^(FIRAuthAppCredential *_Nullable appCredential,
+ NSError *_Nullable error) {
+ if (error) {
+ callback(nil, error);
+ return;
+ }
+ FIRSendVerificationCodeRequest *request =
+ [[FIRSendVerificationCodeRequest alloc] initWithPhoneNumber:phoneNumber
+ appCredential:appCredential
+ APIKey:_auth.APIKey];
+ [FIRAuthBackend sendVerificationCode:request
+ callback:^(FIRSendVerificationCodeResponse *_Nullable response,
+ NSError *_Nullable error) {
+ if (error) {
+ if (error.code == FIRAuthErrorCodeInvalidAppCredential) {
+ if (retryOnInvalidAppCredential) {
+ [_auth.appCredentialManager clearCredential];
+ [self verifyClientAndSendVerificationCodeToPhoneNumber:phoneNumber
+ retryOnInvalidAppCredential:NO
+ callback:callback];
+ return;
+ }
+ callback(nil, [FIRAuthErrorUtils unexpectedResponseWithDeserializedResponse:nil
+ underlyingError:error]);
+ return;
+ }
+ callback(nil, error);
+ return;
+ }
+ // Associate the phone number with the verification ID.
+ response.verificationID.fir_authPhoneNumber = phoneNumber;
+ callback(response.verificationID, nil);
+ }];
+ }];
+}
+
+/** @fn verifyClientWithCompletion:completion:
+ @brief Continues the flow to verify the client via silent push notification.
+ @param completion The callback to be invoked when the client verification flow is finished.
+ */
+- (void)verifyClientWithCompletion:(FIRVerifyClientCallback)completion {
+ if (_auth.appCredentialManager.credential) {
+ completion(_auth.appCredentialManager.credential, nil);
+ return;
+ }
+ [_auth.tokenManager getTokenWithCallback:^(FIRAuthAPNSToken * _Nullable token) {
+ if (!token) {
+ completion(nil, [FIRAuthErrorUtils missingAppTokenError]);
+ return;
+ }
+
+ // Convert token data to hex string.
+ NSUInteger capacity = token.data.length * 2;
+ NSMutableString *tokenString = [NSMutableString stringWithCapacity:capacity];
+ const unsigned char *tokenData = token.data.bytes;
+ for (int idx = 0; idx < token.data.length; ++idx) {
+ [tokenString appendFormat:@"%02X", (int)tokenData[idx]];
+ }
+
+ FIRVerifyClientRequest *request =
+ [[FIRVerifyClientRequest alloc] initWithAppToken:tokenString
+ isSandbox:token.type == FIRAuthAPNSTokenTypeSandbox
+ APIKey:_auth.APIKey];
+ [FIRAuthBackend verifyClient:request callback:^(FIRVerifyClientResponse *_Nullable response,
+ NSError *_Nullable error) {
+ if (error) {
+ completion(nil, error);
+ return;
+ }
+ NSTimeInterval timeout = [response.suggestedTimeOutDate timeIntervalSinceNow];
+ [_auth.appCredentialManager
+ didStartVerificationWithReceipt:response.receipt
+ timeout:timeout
+ callback:^(FIRAuthAppCredential *credential) {
+ if (!credential.secret) {
+ FIRLogError(kFIRLoggerAuth, @"I-AUT000014",
+ @"Failed to receive remote notification to verify app identity within "
+ @"%.0f second(s)", timeout);
+ }
+ completion(credential, nil);
+ }];
+ }];
+ }];
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/AuthProviders/Phone/NSString+FIRAuth.h b/Firebase/Auth/Source/AuthProviders/Phone/NSString+FIRAuth.h
new file mode 100644
index 0000000..ba123fa
--- /dev/null
+++ b/Firebase/Auth/Source/AuthProviders/Phone/NSString+FIRAuth.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @category NSString(FIRAuth)
+ @brief A FIRAuth category for extending the functionality of NSString for specific Firebase Auth
+ use cases.
+ */
+@interface NSString (FIRAuth)
+
+/** @property fir_authPhoneNumber
+ @brief A phone number associated with the verification ID (NSString instance).
+ @remarks Allows an instance on NSString to be associated with a phone number in order to link
+ phone number with the verificationID returned from verifyPhoneNumber:completion:
+ */
+@property(nonatomic, strong) NSString *fir_authPhoneNumber;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/AuthProviders/Phone/NSString+FIRAuth.m b/Firebase/Auth/Source/AuthProviders/Phone/NSString+FIRAuth.m
new file mode 100644
index 0000000..87f3b1c
--- /dev/null
+++ b/Firebase/Auth/Source/AuthProviders/Phone/NSString+FIRAuth.m
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "NSString+FIRAuth.h"
+
+#import <objc/runtime.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@implementation NSString (FIRAuth)
+
+- (void)setFir_authPhoneNumber:(NSString *)phoneNumber {
+ objc_setAssociatedObject(self, @selector(fir_authPhoneNumber), phoneNumber,
+ OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
+
+- (NSString *)fir_authPhoneNumber {
+ return objc_getAssociatedObject(self, @selector(fir_authPhoneNumber));
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/AuthProviders/Twitter/FIRTwitterAuthCredential.h b/Firebase/Auth/Source/AuthProviders/Twitter/FIRTwitterAuthCredential.h
new file mode 100644
index 0000000..5fab4e2
--- /dev/null
+++ b/Firebase/Auth/Source/AuthProviders/Twitter/FIRTwitterAuthCredential.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "../../Private/FIRAuthCredential_Internal.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @class FIRTwitterAuthCredential
+ @brief Internal implementation of FIRAuthCredential for Twitter credentials.
+ */
+@interface FIRTwitterAuthCredential : FIRAuthCredential
+
+/** @property token
+ @brief The Twitter OAuth token.
+ */
+@property(nonatomic, readonly) NSString *token;
+
+/** @property secret
+ @brief The Twitter OAuth secret.
+ */
+@property(nonatomic, readonly) NSString *secret;
+
+/** @fn initWithToken:secret:
+ @brief Designated initializer.
+ @param token The Twitter OAuth token.
+ @param secret The Twitter OAuth secret.
+ */
+- (nullable instancetype)initWithToken:(NSString *)token secret:(NSString *)secret
+ NS_DESIGNATED_INITIALIZER;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/AuthProviders/Twitter/FIRTwitterAuthCredential.m b/Firebase/Auth/Source/AuthProviders/Twitter/FIRTwitterAuthCredential.m
new file mode 100644
index 0000000..6772d6f
--- /dev/null
+++ b/Firebase/Auth/Source/AuthProviders/Twitter/FIRTwitterAuthCredential.m
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRTwitterAuthCredential.h"
+
+#import "FIRTwitterAuthProvider.h"
+#import "FIRAuthExceptionUtils.h"
+#import "FIRVerifyAssertionRequest.h"
+
+@interface FIRTwitterAuthCredential ()
+
+- (nullable instancetype)initWithProvider:(NSString *)provider NS_UNAVAILABLE;
+
+@end
+
+@implementation FIRTwitterAuthCredential
+
+- (nullable instancetype)initWithProvider:(NSString *)provider {
+ [FIRAuthExceptionUtils raiseMethodNotImplementedExceptionWithReason:
+ @"Please call the designated initializer."];
+ return nil;
+}
+
+- (nullable instancetype)initWithToken:(NSString *)token secret:(NSString *)secret {
+ self = [super initWithProvider:FIRTwitterAuthProviderID];
+ if (self) {
+ _token = [token copy];
+ _secret = [secret copy];
+ }
+ return self;
+}
+
+- (void)prepareVerifyAssertionRequest:(FIRVerifyAssertionRequest *)request {
+ request.providerAccessToken = _token;
+ request.providerOAuthTokenSecret = _secret;
+}
+
+@end
diff --git a/Firebase/Auth/Source/AuthProviders/Twitter/FIRTwitterAuthProvider.h b/Firebase/Auth/Source/AuthProviders/Twitter/FIRTwitterAuthProvider.h
new file mode 100644
index 0000000..d8f647d
--- /dev/null
+++ b/Firebase/Auth/Source/AuthProviders/Twitter/FIRTwitterAuthProvider.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "FIRAuthSwiftNameSupport.h"
+
+@class FIRAuthCredential;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ @brief A string constant identifying the Twitter identity provider.
+ */
+extern NSString *const FIRTwitterAuthProviderID FIR_SWIFT_NAME(TwitterAuthProviderID);
+
+/** @class FIRTwitterAuthProvider
+ @brief Utility class for constructing Twitter credentials.
+ */
+FIR_SWIFT_NAME(TwitterAuthProvider)
+@interface FIRTwitterAuthProvider : NSObject
+
+/** @fn credentialWithToken:secret:
+ @brief Creates an @c FIRAuthCredential for a Twitter sign in.
+
+ @param token The Twitter OAuth token.
+ @param secret The Twitter OAuth secret.
+ @return A FIRAuthCredential containing the Twitter credential.
+ */
++ (FIRAuthCredential *)credentialWithToken:(NSString *)token secret:(NSString *)secret;
+
+/** @fn init
+ @brief This class is not meant to be initialized.
+ */
+- (instancetype)init NS_UNAVAILABLE;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/AuthProviders/Twitter/FIRTwitterAuthProvider.m b/Firebase/Auth/Source/AuthProviders/Twitter/FIRTwitterAuthProvider.m
new file mode 100644
index 0000000..5d738ce
--- /dev/null
+++ b/Firebase/Auth/Source/AuthProviders/Twitter/FIRTwitterAuthProvider.m
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRTwitterAuthProvider.h"
+
+#import "FIRTwitterAuthCredential.h"
+#import "FIRAuthExceptionUtils.h"
+
+// FIRTwitterAuthProviderID is defined in FIRAuthProvider.m.
+
+@implementation FIRTwitterAuthProvider
+
+- (instancetype)init {
+ [FIRAuthExceptionUtils raiseMethodNotImplementedExceptionWithReason:
+ @"This class is not meant to be initialized."];
+ return nil;
+}
+
++ (FIRAuthCredential *)credentialWithToken:(NSString *)token secret:(NSString *)secret {
+ return [[FIRTwitterAuthCredential alloc] initWithToken:token secret:secret];
+}
+
+@end
diff --git a/Firebase/Auth/Source/FIRActionCodeSettings.m b/Firebase/Auth/Source/FIRActionCodeSettings.m
new file mode 100644
index 0000000..26d7538
--- /dev/null
+++ b/Firebase/Auth/Source/FIRActionCodeSettings.m
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "Private/FIRActionCodeSettings.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@implementation FIRActionCodeSettings
+
+- (void)setIOSBundleID:(NSString *)iOSBundleID
+ appStoreID:(nullable NSString *)appStoreID {
+ _iOSBundleID = [iOSBundleID copy];
+ _iOSAppStoreID = [appStoreID copy];
+}
+
+- (void)setAndroidPackageName:(NSString *)androidPackageName
+ installIfNotAvailable:(BOOL)installIfNotAvailable
+ minimumVersion:(nullable NSString *)minimumVersion {
+ _androidPackageName = [androidPackageName copy];
+ _androidInstallIfNotAvailable = installIfNotAvailable;
+ _androidMinimumVersion = [minimumVersion copy];
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/FIRAdditionalUserInfo.h b/Firebase/Auth/Source/FIRAdditionalUserInfo.h
new file mode 100644
index 0000000..70e9e57
--- /dev/null
+++ b/Firebase/Auth/Source/FIRAdditionalUserInfo.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "FIRAuthSwiftNameSupport.h"
+
+@class FIRVerifyAssertionResponse;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @class FIRAdditionalUserInfo
+ @brief Represents additional user data returned from an identity provider.
+ */
+FIR_SWIFT_NAME(AdditionalUserInfo)
+@interface FIRAdditionalUserInfo : NSObject
+
+/** @fn init
+ @brief This class should not be initialized manually. @c FIRAdditionalUserInfo can be retrieved
+ from @c FIRAuthDataResult .
+ */
+- (instancetype)init NS_UNAVAILABLE;
+
+/** @property providerID
+ @brief The provider identifier.
+ */
+@property(nonatomic, readonly) NSString *providerID;
+
+/** @property profile
+ @brief profile Dictionary containing the additional IdP specific information.
+ */
+@property(nonatomic, readonly, nullable) NSDictionary<NSString *, NSObject *> *profile;
+
+/** @property username
+ @brief username The name of the user.
+ */
+@property(nonatomic, readonly, nullable) NSString *username;
+
+/** @property newUser
+ @brief Indicates whether or not the current user was signed in for the first time.
+ */
+@property(nonatomic, readonly, getter=isNewUser) BOOL newUser;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/FIRAdditionalUserInfo.m b/Firebase/Auth/Source/FIRAdditionalUserInfo.m
new file mode 100644
index 0000000..e00347d
--- /dev/null
+++ b/Firebase/Auth/Source/FIRAdditionalUserInfo.m
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "Private/FIRAdditionalUserInfo_Internal.h"
+
+#import "FIRVerifyAssertionResponse.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@implementation FIRAdditionalUserInfo
+
+/** @var kProviderIDCodingKey
+ @brief The key used to encode the providerID property for NSSecureCoding.
+ */
+static NSString *const kProviderIDCodingKey = @"providerID";
+
+/** @var kProfileCodingKey
+ @brief The key used to encode the profile property for NSSecureCoding.
+ */
+static NSString *const kProfileCodingKey = @"profile";
+
+/** @var kUsernameCodingKey
+ @brief The key used to encode the username property for NSSecureCoding.
+ */
+static NSString *const kUsernameCodingKey = @"username";
+
+/** @var kNewUserKey
+ @brief The key used to encode the newUser property for NSSecureCoding.
+ */
+static NSString *const kNewUserKey = @"newUser";
+
++ (nullable instancetype)userInfoWithVerifyAssertionResponse:
+ (FIRVerifyAssertionResponse *)verifyAssertionResponse {
+ return [[self alloc] initWithProviderID:verifyAssertionResponse.providerID
+ profile:verifyAssertionResponse.profile
+ username:verifyAssertionResponse.username
+ isNewUser:verifyAssertionResponse.isNewUser];
+}
+
+- (nullable instancetype)initWithProviderID:(NSString *)providerID
+ profile:(nullable NSDictionary<NSString *, NSObject *> *)profile
+ username:(nullable NSString *)username
+ isNewUser:(BOOL)isNewUser {
+ self = [super init];
+ if (self) {
+ _providerID = [providerID copy];
+ if (profile) {
+ _profile = [[NSDictionary alloc] initWithDictionary:profile copyItems:YES];
+ }
+ _username = [username copy];
+ _newUser = isNewUser;
+ }
+ return self;
+}
+
+#pragma mark - NSSecureCoding
+
++ (BOOL)supportsSecureCoding {
+ return YES;
+}
+
+- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder {
+ NSString *providerID =
+ [aDecoder decodeObjectOfClass:[NSString class] forKey:kProviderIDCodingKey];
+ NSDictionary<NSString *, NSObject *> *profile =
+ [aDecoder decodeObjectOfClass:[NSDictionary class] forKey:kProfileCodingKey];
+ NSString *username = [aDecoder decodeObjectOfClass:[NSString class] forKey:kUsernameCodingKey];
+ NSNumber *isNewUser = [aDecoder decodeObjectOfClass:[NSNumber class] forKey:kNewUserKey];
+
+ return [self initWithProviderID:providerID
+ profile:profile
+ username:username
+ isNewUser:isNewUser.boolValue];
+}
+
+- (void)encodeWithCoder:(NSCoder *)aCoder {
+ [aCoder encodeObject:_providerID forKey:kProviderIDCodingKey];
+ [aCoder encodeObject:_profile forKey:kProfileCodingKey];
+ [aCoder encodeObject:_username forKey:kUsernameCodingKey];
+ [aCoder encodeObject:[NSNumber numberWithBool:_newUser] forKey:kNewUserKey];
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/FIRAuth.h b/Firebase/Auth/Source/FIRAuth.h
new file mode 100644
index 0000000..b913380
--- /dev/null
+++ b/Firebase/Auth/Source/FIRAuth.h
@@ -0,0 +1,612 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "FIRAuthAPNSTokenType.h"
+#import "FIRAuthErrors.h"
+#import "FIRAuthSwiftNameSupport.h"
+
+@class FIRApp;
+@class FIRAuth;
+@class FIRAuthCredential;
+@class FIRAuthDataResult;
+@class FIRUser;
+@protocol FIRAuthStateListener;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @typedef FIRAuthStateDidChangeListenerHandle
+ @brief The type of handle returned by @c FIRAuth.addAuthStateDidChangeListener:.
+ */
+typedef id<NSObject> FIRAuthStateDidChangeListenerHandle
+ FIR_SWIFT_NAME(AuthStateDidChangeListenerHandle);
+
+/** @typedef FIRAuthStateDidChangeListenerBlock
+ @brief The type of block which can be registered as a listener for auth state did change events.
+
+ @param auth The FIRAuth object on which state changes occurred.
+ @param user Optionally; the current signed in user, if any.
+ */
+typedef void(^FIRAuthStateDidChangeListenerBlock)(FIRAuth *auth, FIRUser *_Nullable user)
+ FIR_SWIFT_NAME(AuthStateDidChangeListenerBlock);
+
+/** @typedef FIRIDTokenDidChangeListenerHandle
+ @brief The type of handle returned by @c FIRAuth.addIDTokenDidChangeListener:.
+ */
+typedef id<NSObject> FIRIDTokenDidChangeListenerHandle
+ FIR_SWIFT_NAME(IDTokenDidChangeListenerHandle);
+
+/** @typedef FIRIDTokenDidChangeListenerBlock
+ @brief The type of block which can be registered as a listener for ID token did change events.
+
+ @param auth The FIRAuth object on which ID token changes occurred.
+ @param user Optionally; the current signed in user, if any.
+ */
+typedef void(^FIRIDTokenDidChangeListenerBlock)(FIRAuth *auth, FIRUser *_Nullable user)
+ FIR_SWIFT_NAME(IDTokenDidChangeListenerBlock);
+
+/** @typedef FIRAuthDataResultCallback
+ @brief The type of block invoked when sign-in related events complete.
+
+ @param authResult Optionally; Result of sign-in request containing @c FIRUser and
+ @c FIRAdditionalUserInfo.
+ @param error Optionally; the error which occurred - or nil if the request was successful.
+ */
+typedef void (^FIRAuthDataResultCallback)(FIRAuthDataResult *_Nullable authResult,
+ NSError *_Nullable error)
+ FIR_SWIFT_NAME(AuthDataResultCallback);
+
+#if defined(__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
+/**
+ @brief The name of the @c NSNotificationCenter notification which is posted when the auth state
+ changes (for example, a new token has been produced, a user signs in or signs out). The
+ object parameter of the notification is the sender @c FIRAuth instance.
+ */
+extern const NSNotificationName FIRAuthStateDidChangeNotification
+ FIR_SWIFT_NAME(AuthStateDidChange);
+#else
+/**
+ @brief The name of the @c NSNotificationCenter notification which is posted when the auth state
+ changes (for example, a new token has been produced, a user signs in or signs out). The
+ object parameter of the notification is the sender @c FIRAuth instance.
+ */
+extern NSString *const FIRAuthStateDidChangeNotification
+ FIR_SWIFT_NAME(AuthStateDidChangeNotification);
+#endif // defined(__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
+
+/** @typedef FIRAuthResultCallback
+ @brief The type of block invoked when sign-in related events complete.
+
+ @param user Optionally; the signed in user, if any.
+ @param error Optionally; if an error occurs, this is the NSError object that describes the
+ problem. Set to nil otherwise.
+ */
+typedef void (^FIRAuthResultCallback)(FIRUser *_Nullable user, NSError *_Nullable error)
+ FIR_SWIFT_NAME(AuthResultCallback);
+
+/** @typedef FIRProviderQueryCallback
+ @brief The type of block invoked when a list of identity providers for a given email address is
+ requested.
+
+ @param providers Optionally; a list of provider identifiers, if any.
+ @see FIRGoogleAuthProviderID etc.
+ @param error Optionally; if an error occurs, this is the NSError object that describes the
+ problem. Set to nil otherwise.
+ */
+typedef void (^FIRProviderQueryCallback)(NSArray<NSString *> *_Nullable providers,
+ NSError *_Nullable error)
+ FIR_SWIFT_NAME(ProviderQueryCallback);
+
+/** @typedef FIRSendPasswordResetCallback
+ @brief The type of block invoked when sending a password reset email.
+
+ @param error Optionally; if an error occurs, this is the NSError object that describes the
+ problem. Set to nil otherwise.
+ */
+typedef void (^FIRSendPasswordResetCallback)(NSError *_Nullable error)
+ FIR_SWIFT_NAME(SendPasswordResetCallback);
+
+/** @typedef FIRConfirmPasswordResetCallback
+ @brief The type of block invoked when performing a password reset.
+
+ @param error Optionally; if an error occurs, this is the NSError object that describes the
+ problem. Set to nil otherwise.
+ */
+typedef void (^FIRConfirmPasswordResetCallback)(NSError *_Nullable error)
+ FIR_SWIFT_NAME(ConfirmPasswordResetCallback);
+
+/** @typedef FIRVerifyPasswordResetCodeCallback
+ @brief The type of block invoked when verifying that an out of band code should be used to
+ perform password reset.
+
+ @param email Optionally; the email address of the user for which the out of band code applies.
+ @param error Optionally; if an error occurs, this is the NSError object that describes the
+ problem. Set to nil otherwise.
+ */
+typedef void (^FIRVerifyPasswordResetCodeCallback)(NSString *_Nullable email,
+ NSError *_Nullable error)
+ FIR_SWIFT_NAME(VerifyPasswordResetCodeCallback);
+
+/** @typedef FIRApplyActionCodeCallback
+ @brief The type of block invoked when applying an action code.
+
+ @param error Optionally; if an error occurs, this is the NSError object that describes the
+ problem. Set to nil otherwise.
+ */
+typedef void (^FIRApplyActionCodeCallback)(NSError *_Nullable error)
+ FIR_SWIFT_NAME(ApplyActionCodeCallback);
+
+/**
+ @brief Keys used to retrieve operation data from a @c FIRActionCodeInfo object by the @c
+ dataForKey method.
+ */
+typedef NS_ENUM(NSInteger, FIRActionDataKey) {
+ /**
+ * The email address to which the code was sent.
+ * For FIRActionCodeOperationRecoverEmail, the new email address for the account.
+ */
+ FIRActionCodeEmailKey = 0,
+
+ /** For FIRActionCodeOperationRecoverEmail, the current email address for the account. */
+ FIRActionCodeFromEmailKey = 1
+} FIR_SWIFT_NAME(ActionDataKey);
+
+/** @class FIRActionCodeInfo
+ @brief Manages information regarding action codes.
+ */
+FIR_SWIFT_NAME(ActionCodeInfo)
+@interface FIRActionCodeInfo : NSObject
+
+/**
+ @brief Operations which can be performed with action codes.
+ */
+typedef NS_ENUM(NSInteger, FIRActionCodeOperation) {
+ /** Action code for unknown operation. */
+ FIRActionCodeOperationUnknown = 0,
+
+ /** Action code for password reset operation. */
+ FIRActionCodeOperationPasswordReset = 1,
+
+ /** Action code for verify email operation. */
+ FIRActionCodeOperationVerifyEmail = 2
+} FIR_SWIFT_NAME(ActionCodeOperation);
+
+/**
+ @brief The operation being performed.
+ */
+@property(nonatomic, readonly) FIRActionCodeOperation operation;
+
+/** @fn dataForKey:
+ @brief The operation being performed.
+
+ @param key The FIRActionDataKey value used to retrieve the operation data.
+
+ @return The operation data pertaining to the provided action code key.
+ */
+- (NSString *)dataForKey:(FIRActionDataKey)key;
+
+/** @fn init
+ @brief please use initWithOperation: instead.
+ */
+- (instancetype)init NS_UNAVAILABLE;
+
+@end
+
+/** @typedef FIRCheckActionCodeCallBack
+ @brief The type of block invoked when performing a check action code operation.
+
+ @param info Metadata corresponding to the action code.
+ @param error Optionally; if an error occurs, this is the NSError object that describes the
+ problem. Set to nil otherwise.
+ */
+typedef void (^FIRCheckActionCodeCallBack)(FIRActionCodeInfo *_Nullable info,
+ NSError *_Nullable error)
+ FIR_SWIFT_NAME(CheckActionCodeCallback);
+
+/** @class FIRAuth
+ @brief Manages authentication for Firebase apps.
+ @remarks This class is thread-safe.
+ */
+FIR_SWIFT_NAME(Auth)
+@interface FIRAuth : NSObject
+
+/** @fn auth
+ @brief Gets the auth object for the default Firebase app.
+ @remarks The default Firebase app must have already been configured or an exception will be
+ raised.
+ */
++ (FIRAuth *)auth FIR_SWIFT_NAME(auth());
+
+/** @fn authWithApp:
+ @brief Gets the auth object for a @c FIRApp.
+
+ @param app The FIRApp for which to retrieve the associated FIRAuth instance.
+ @return The FIRAuth instance associated with the given FIRApp.
+ */
++ (FIRAuth *)authWithApp:(FIRApp *)app FIR_SWIFT_NAME(auth(app:));
+
+/** @property app
+ @brief Gets the @c FIRApp object that this auth object is connected to.
+ */
+@property(nonatomic, weak, readonly, nullable) FIRApp *app;
+
+/** @property currentUser
+ @brief Synchronously gets the cached current user, or null if there is none.
+ */
+@property(nonatomic, strong, readonly, nullable) FIRUser *currentUser;
+
+/** @property APNSToken
+ @brief The APNs token used for phone number authentication. The type of the token (production
+ or sandbox) will be attempted to be automatcially detected.
+ @remarks If swizzling is disabled, the APNs Token must be set for phone number auth to work,
+ by either setting this property or by calling @c setAPNSToken:type:
+ */
+@property(nonatomic, strong, nullable) NSData *APNSToken;
+
+/** @fn init
+ @brief Please access auth instances using @c FIRAuth.auth and @c FIRAuth.authForApp:.
+ */
+- (instancetype)init NS_UNAVAILABLE;
+
+/** @fn fetchProvidersForEmail:completion:
+ @brief Fetches the list of IdPs that can be used for signing in with the provided email address.
+ Useful for an "identifier-first" sign-in flow.
+
+ @param email The email address for which to obtain a list of identity providers.
+ @param completion Optionally; a block which is invoked when the list of providers for the
+ specified email address is ready or an error was encountered. Invoked asynchronously on the
+ main thread in the future.
+
+ @remarks Possible error codes:
+ <ul>
+ <li>@c FIRAuthErrorCodeInvalidEmail - Indicates the email address is malformed.</li>
+ </ul>
+
+ @remarks See @c FIRAuthErrors for a list of error codes that are common to all API methods.
+ */
+- (void)fetchProvidersForEmail:(NSString *)email
+ completion:(nullable FIRProviderQueryCallback)completion;
+
+/** @fn signInWithEmail:password:completion:
+ @brief Signs in using an email address and password.
+
+ @param email The user's email address.
+ @param password The user's password.
+ @param completion Optionally; a block which is invoked when the sign in flow finishes, or is
+ canceled. Invoked asynchronously on the main thread in the future.
+
+ @remarks Possible error codes:
+
+ <ul>
+ <li>@c FIRAuthErrorCodeOperationNotAllowed - Indicates that email and password
+ accounts are not enabled. Enable them in the Auth section of the
+ Firebase console.
+ </li>
+ <li>@c FIRAuthErrorCodeUserDisabled - Indicates the user's account is disabled.
+ </li>
+ <li>@c FIRAuthErrorCodeWrongPassword - Indicates the user attempted
+ sign in with an incorrect password.
+ </li>
+ <li>@c FIRAuthErrorCodeInvalidEmail - Indicates the email address is malformed.
+ </li>
+ </ul>
+
+ @remarks See @c FIRAuthErrors for a list of error codes that are common to all API methods.
+ */
+- (void)signInWithEmail:(NSString *)email
+ password:(NSString *)password
+ completion:(nullable FIRAuthResultCallback)completion;
+
+/** @fn signInWithCredential:completion:
+ @brief Convenience method for @c signInAndRetrieveDataWithCredential:completion: This method
+ doesn't return additional identity provider data.
+ */
+- (void)signInWithCredential:(FIRAuthCredential *)credential
+ completion:(nullable FIRAuthResultCallback)completion;
+
+/** @fn signInAndRetrieveDataWithCredential:completion:
+ @brief Asynchronously signs in to Firebase with the given 3rd-party credentials (e.g. a Facebook
+ login Access Token, a Google ID Token/Access Token pair, etc.) and returns additional
+ identity provider data.
+
+ @param credential The credential supplied by the IdP.
+ @param completion Optionally; a block which is invoked when the sign in flow finishes, or is
+ canceled. Invoked asynchronously on the main thread in the future.
+
+ @remarks Possible error codes:
+ <ul>
+ <li>@c FIRAuthErrorCodeInvalidCredential - Indicates the supplied credential is invalid.
+ This could happen if it has expired or it is malformed.
+ </li>
+ <li>@c FIRAuthErrorCodeOperationNotAllowed - Indicates that accounts
+ with the identity provider represented by the credential are not enabled.
+ Enable them in the Auth section of the Firebase console.
+ </li>
+ <li>@c FIRAuthErrorCodeAccountExistsWithDifferentCredential - Indicates the email asserted
+ by the credential (e.g. the email in a Facebook access token) is already in use by an
+ existing account, that cannot be authenticated with this sign-in method. Call
+ fetchProvidersForEmail for this user’s email and then prompt them to sign in with any of
+ the sign-in providers returned. This error will only be thrown if the "One account per
+ email address" setting is enabled in the Firebase console, under Auth settings.
+ </li>
+ <li>@c FIRAuthErrorCodeUserDisabled - Indicates the user's account is disabled.
+ </li>
+ <li>@c FIRAuthErrorCodeWrongPassword - Indicates the user attempted sign in with an
+ incorrect password, if credential is of the type EmailPasswordAuthCredential.
+ </li>
+ <li>@c FIRAuthErrorCodeInvalidEmail - Indicates the email address is malformed.
+ </li>
+ </ul>
+
+ @remarks See @c FIRAuthErrors for a list of error codes that are common to all API methods.
+ */
+- (void)signInAndRetrieveDataWithCredential:(FIRAuthCredential *)credential
+ completion:(nullable FIRAuthDataResultCallback)completion;
+
+/** @fn signInAnonymouslyWithCompletion:
+ @brief Asynchronously creates and becomes an anonymous user.
+ @param completion Optionally; a block which is invoked when the sign in finishes, or is
+ canceled. Invoked asynchronously on the main thread in the future.
+
+ @remarks If there is already an anonymous user signed in, that user will be returned instead.
+ If there is any other existing user signed in, that user will be signed out.
+
+ @remarks Possible error codes:
+ <ul>
+ <li>@c FIRAuthErrorCodeOperationNotAllowed - Indicates that anonymous accounts are
+ not enabled. Enable them in the Auth section of the Firebase console.
+ </li>
+ </ul>
+
+ @remarks See @c FIRAuthErrors for a list of error codes that are common to all API methods.
+ */
+- (void)signInAnonymouslyWithCompletion:(nullable FIRAuthResultCallback)completion;
+
+/** @fn signInWithCustomToken:completion:
+ @brief Asynchronously signs in to Firebase with the given Auth token.
+
+ @param token A self-signed custom auth token.
+ @param completion Optionally; a block which is invoked when the sign in finishes, or is
+ canceled. Invoked asynchronously on the main thread in the future.
+
+ @remarks Possible error codes:
+ <ul>
+ <li>@c FIRAuthErrorCodeInvalidCustomToken - Indicates a validation error with
+ the custom token.
+ </li>
+ <li>@c FIRAuthErrorCodeCustomTokenMismatch - Indicates the service account and the API key
+ belong to different projects.
+ </li>
+ </ul>
+
+ @remarks See @c FIRAuthErrors for a list of error codes that are common to all API methods.
+ */
+- (void)signInWithCustomToken:(NSString *)token
+ completion:(nullable FIRAuthResultCallback)completion;
+
+/** @fn createUserWithEmail:password:completion:
+ @brief Creates and, on success, signs in a user with the given email address and password.
+
+ @param email The user's email address.
+ @param password The user's desired password.
+ @param completion Optionally; a block which is invoked when the sign up flow finishes, or is
+ canceled. Invoked asynchronously on the main thread in the future.
+
+ @remarks Possible error codes:
+ <ul>
+ <li>@c FIRAuthErrorCodeInvalidEmail - Indicates the email address is malformed.
+ </li>
+ <li>@c FIRAuthErrorCodeEmailAlreadyInUse - Indicates the email used to attempt sign up
+ already exists. Call fetchProvidersForEmail to check which sign-in mechanisms the user
+ used, and prompt the user to sign in with one of those.
+ </li>
+ <li>@c FIRAuthErrorCodeOperationNotAllowed - Indicates that email and password accounts
+ are not enabled. Enable them in the Auth section of the Firebase console.
+ </li>
+ <li>@c FIRAuthErrorCodeWeakPassword - Indicates an attempt to set a password that is
+ considered too weak. The NSLocalizedFailureReasonErrorKey field in the NSError.userInfo
+ dictionary object will contain more detailed explanation that can be shown to the user.
+ </li>
+ </ul>
+
+ @remarks See @c FIRAuthErrors for a list of error codes that are common to all API methods.
+ */
+- (void)createUserWithEmail:(NSString *)email
+ password:(NSString *)password
+ completion:(nullable FIRAuthResultCallback)completion;
+
+/** @fn confirmPasswordResetWithCode:newPassword:completion:
+ @brief Resets the password given a code sent to the user outside of the app and a new password
+ for the user.
+
+ @param newPassword The new password.
+ @param completion Optionally; a block which is invoked when the request finishes. Invoked
+ asynchronously on the main thread in the future.
+
+ @remarks Possible error codes:
+ <ul>
+ <li>@c FIRAuthErrorCodeWeakPassword - Indicates an attempt to set a password that is
+ considered too weak.
+ </li>
+ <li>@c FIRAuthErrorCodeOperationNotAllowed - Indicates the administrator disabled sign
+ in with the specified identity provider.
+ </li>
+ <li>@c FIRAuthErrorCodeExpiredActionCode - Indicates the OOB code is expired.
+ </li>
+ <li>@c FIRAuthErrorCodeInvalidActionCode - Indicates the OOB code is invalid.
+ </li>
+ </ul>
+
+ @remarks See @c FIRAuthErrors for a list of error codes that are common to all API methods.
+ */
+- (void)confirmPasswordResetWithCode:(NSString *)code
+ newPassword:(NSString *)newPassword
+ completion:(FIRConfirmPasswordResetCallback)completion;
+
+/** @fn checkActionCode:completion:
+ @brief Checks the validity of an out of band code.
+
+ @param code The out of band code to check validity.
+ @param completion Optionally; a block which is invoked when the request finishes. Invoked
+ asynchronously on the main thread in the future.
+ */
+- (void)checkActionCode:(NSString *)code completion:(FIRCheckActionCodeCallBack)completion;
+
+/** @fn verifyPasswordResetCode:completion:
+ @brief Checks the validity of a verify password reset code.
+
+ @param code The password reset code to be verified.
+ @param completion Optionally; a block which is invoked when the request finishes. Invoked
+ asynchronously on the main thread in the future.
+ */
+- (void)verifyPasswordResetCode:(NSString *)code
+ completion:(FIRVerifyPasswordResetCodeCallback)completion;
+
+/** @fn applyActionCode:completion:
+ @brief Applies out of band code.
+
+ @param code The out of band code to be applied.
+ @param completion Optionally; a block which is invoked when the request finishes. Invoked
+ asynchronously on the main thread in the future.
+
+ @remarks This method will not work for out of band codes which require an additional parameter,
+ such as password reset code.
+ */
+- (void)applyActionCode:(NSString *)code
+ completion:(FIRApplyActionCodeCallback)completion;
+
+/** @fn sendPasswordResetWithEmail:completion:
+ @brief Initiates a password reset for the given email address.
+
+ @param email The email address of the user.
+ @param completion Optionally; a block which is invoked when the request finishes. Invoked
+ asynchronously on the main thread in the future.
+
+ @remarks Possible error codes:
+ <ul>
+ <li>@c FIRAuthErrorCodeInvalidRecipientEmail - Indicates an invalid recipient email was
+ sent in the request.
+ </li>
+ <li>@c FIRAuthErrorCodeInvalidSender - Indicates an invalid sender email is set in
+ the console for this action.
+ </li>
+ <li>@c FIRAuthErrorCodeInvalidMessagePayload - Indicates an invalid email template for
+ sending update email.
+ </li>
+ </ul>
+ */
+- (void)sendPasswordResetWithEmail:(NSString *)email
+ completion:(nullable FIRSendPasswordResetCallback)completion;
+
+/** @fn signOut:
+ @brief Signs out the current user.
+
+ @param error Optionally; if an error occurs, upon return contains an NSError object that
+ describes the problem; is nil otherwise.
+ @return @YES when the sign out request was successful. @NO otherwise.
+
+ @remarks Possible error codes:
+ <ul>
+ <li>@c FIRAuthErrorCodeKeychainError - Indicates an error occurred when accessing the
+ keychain. The @c NSLocalizedFailureReasonErrorKey field in the @c NSError.userInfo
+ dictionary will contain more information about the error encountered.
+ </li>
+ </ul>
+
+ */
+- (BOOL)signOut:(NSError *_Nullable *_Nullable)error;
+
+/** @fn addAuthStateDidChangeListener:
+ @brief Registers a block as an "auth state did change" listener. To be invoked when:
+
+ + The block is registered as a listener,
+ + A user with a different UID from the current user has signed in, or
+ + The current user has signed out.
+
+ @param listener The block to be invoked. The block is always invoked asynchronously on the main
+ thread, even for it's initial invocation after having been added as a listener.
+
+ @remarks The block is invoked immediately after adding it according to it's standard invocation
+ semantics, asynchronously on the main thread. Users should pay special attention to
+ making sure the block does not inadvertently retain objects which should not be retained by
+ the long-lived block. The block itself will be retained by @c FIRAuth until it is
+ unregistered or until the @c FIRAuth instance is otherwise deallocated.
+
+ @return A handle useful for manually unregistering the block as a listener.
+ */
+- (FIRAuthStateDidChangeListenerHandle)addAuthStateDidChangeListener:
+ (FIRAuthStateDidChangeListenerBlock)listener;
+
+/** @fn removeAuthStateDidChangeListener:
+ @brief Unregisters a block as an "auth state did change" listener.
+
+ @param listenerHandle The handle for the listener.
+ */
+- (void)removeAuthStateDidChangeListener:(FIRAuthStateDidChangeListenerHandle)listenerHandle;
+
+/** @fn addIDTokenDidChangeListener:
+ @brief Registers a block as an "ID token did change" listener. To be invoked when:
+
+ + The block is registered as a listener,
+ + A user with a different UID from the current user has signed in,
+ + The ID token of the current user has been refreshed, or
+ + The current user has signed out.
+
+ @param listener The block to be invoked. The block is always invoked asynchronously on the main
+ thread, even for it's initial invocation after having been added as a listener.
+
+ @remarks The block is invoked immediately after adding it according to it's standard invocation
+ semantics, asynchronously on the main thread. Users should pay special attention to
+ making sure the block does not inadvertently retain objects which should not be retained by
+ the long-lived block. The block itself will be retained by @c FIRAuth until it is
+ unregistered or until the @c FIRAuth instance is otherwise deallocated.
+
+ @return A handle useful for manually unregistering the block as a listener.
+ */
+- (FIRIDTokenDidChangeListenerHandle)addIDTokenDidChangeListener:
+ (FIRIDTokenDidChangeListenerBlock)listener;
+
+/** @fn removeIDTokenDidChangeListener:
+ @brief Unregisters a block as an "ID token did change" listener.
+
+ @param listenerHandle The handle for the listener.
+ */
+- (void)removeIDTokenDidChangeListener:(FIRIDTokenDidChangeListenerHandle)listenerHandle;
+
+/** @fn setAPNSToken:type:
+ @brief Sets the APNs token along with its type.
+ @remarks If swizzling is disabled, the APNs Token must be set for phone number auth to work,
+ by either setting calling this method or by setting the @c APNSToken property.
+ */
+- (void)setAPNSToken:(NSData *)token type:(FIRAuthAPNSTokenType)type;
+
+/** @fn canHandleNotification:
+ @brief Whether the specific remote notification is handled by @c FIRAuth .
+ @param userInfo A dictionary that contains information related to the
+ notification in question.
+ @return Whether or the notification is handled. @c YES means the notification is for @c FIRAuth
+ so the caller should ignore the notification from further processing, and @c NO means the
+ the notification is for the app (or another libaray) so the caller should continue handling
+ this notification as usual.
+ @remarks If swizzling is disabled, related remote notifications must be forwarded to this method
+ for phone number auth to work.
+ */
+- (BOOL)canHandleNotification:(NSDictionary *)userInfo;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/FIRAuth.m b/Firebase/Auth/Source/FIRAuth.m
new file mode 100644
index 0000000..d1beae6
--- /dev/null
+++ b/Firebase/Auth/Source/FIRAuth.m
@@ -0,0 +1,1252 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "Private/FIRAuth_Internal.h"
+
+#import "FIRAppAssociationRegistration.h"
+#import "FIRAppInternal.h"
+#import "FIROptions.h"
+#import "FIRLogger.h"
+#import "AuthProviders/EmailPassword/FIREmailPasswordAuthCredential.h"
+#import "AuthProviders/Phone/FIRPhoneAuthCredential_Internal.h"
+#import "Private/FIRAdditionalUserInfo_Internal.h"
+#import "Private/FIRAuthAPNSToken.h"
+#import "Private/FIRAuthAPNSTokenManager.h"
+#import "Private/FIRAuthAppCredentialManager.h"
+#import "Private/FIRAuthAppDelegateProxy.h"
+#import "Private/FIRAuthCredential_Internal.h"
+#import "Private/FIRAuthDataResult_Internal.h"
+#import "Private/FIRAuthDispatcher.h"
+#import "Private/FIRAuthErrorUtils.h"
+#import "FIRAuthExceptionUtils.h"
+#import "Private/FIRAuthGlobalWorkQueue.h"
+#import "Private/FIRAuthKeychain.h"
+#import "Private/FIRAuthNotificationManager.h"
+#import "Private/FIRUser_Internal.h"
+#import "FirebaseAuth.h"
+#import "FIRAuthBackend.h"
+#import "FIRCreateAuthURIRequest.h"
+#import "FIRCreateAuthURIResponse.h"
+#import "FIRGetOOBConfirmationCodeRequest.h"
+#import "FIRGetOOBConfirmationCodeResponse.h"
+#import "FIRResetPasswordRequest.h"
+#import "FIRResetPasswordResponse.h"
+#import "FIRSendVerificationCodeRequest.h"
+#import "FIRSendVerificationCodeResponse.h"
+#import "FIRSetAccountInfoRequest.h"
+#import "FIRSetAccountInfoResponse.h"
+#import "FIRSignUpNewUserRequest.h"
+#import "FIRSignUpNewUserResponse.h"
+#import "FIRVerifyAssertionRequest.h"
+#import "FIRVerifyAssertionResponse.h"
+#import "FIRVerifyCustomTokenRequest.h"
+#import "FIRVerifyCustomTokenResponse.h"
+#import "FIRVerifyPasswordRequest.h"
+#import "FIRVerifyPasswordResponse.h"
+#import "FIRVerifyPhoneNumberRequest.h"
+#import "FIRVerifyPhoneNumberResponse.h"
+
+#pragma mark - Constants
+
+NSString *const FIRAuthStateDidChangeInternalNotification =
+ @"FIRAuthStateDidChangeInternalNotification";
+NSString *const FIRAuthStateDidChangeInternalNotificationTokenKey =
+ @"FIRAuthStateDidChangeInternalNotificationTokenKey";
+
+#if defined(__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
+const NSNotificationName FIRAuthStateDidChangeNotification = @"FIRAuthStateDidChangeNotification";
+#else
+NSString *const FIRAuthStateDidChangeNotification = @"FIRAuthStateDidChangeNotification";
+#endif // defined(__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
+
+/** @var kMaxWaitTimeForBackoff
+ @brief The maximum wait time before attempting to retry auto refreshing tokens after a failed
+ attempt.
+ @remarks This is the upper limit (in seconds) of the exponential backoff used for retrying
+ token refresh.
+ */
+static NSTimeInterval kMaxWaitTimeForBackoff = 16 * 60;
+
+/** @var kTokenRefreshHeadStart
+ @brief The amount of time before the token expires that proactive refresh should be attempted.
+ */
+NSTimeInterval kTokenRefreshHeadStart = 5 * 60;
+
+/** @var kUserKey
+ @brief Key of user stored in the keychain. Prefixed with a Firebase app name.
+ */
+static NSString *const kUserKey = @"%@_firebase_user";
+
+/** @var kMissingEmailInvalidParameterExceptionReason
+ @brief The key of missing email key @c invalidParameterException.
+ */
+static NSString *const kEmailInvalidParameterReason = @"The email used to initiate user password "
+ "cannot be nil";
+
+static NSString *const kPasswordResetRequestType = @"PASSWORD_RESET";
+
+static NSString *const kVerifyEmailRequestType = @"VERIFY_EMAIL";
+
+/** @var kMissingPasswordReason
+ @brief The reason why the @c FIRAuthErrorCodeWeakPassword error is thrown.
+ @remarks This error message will be localized in the future.
+ */
+static NSString *const kMissingPasswordReason = @"Missing Password";
+
+/** @var gKeychainServiceNameForAppName
+ @brief A map from Firebase app name to keychain service names.
+ @remarks This map is needed for looking up the keychain service name after the FIRApp instance
+ is deleted, to remove the associated keychain item. Accessing should occur within a
+ @syncronized([FIRAuth class]) context.
+ */
+static NSMutableDictionary *gKeychainServiceNameForAppName;
+
+#pragma mark - FIRActionCodeInfo
+
+@implementation FIRActionCodeInfo {
+ /** @var _email
+ @brief The email address to which the code was sent. The new email address in the case of
+ FIRActionCodeOperationRecoverEmail.
+ */
+ NSString *_email;
+
+ /** @var _fromEmail
+ @brief The current email address in the case of FIRActionCodeOperationRecoverEmail.
+ */
+ NSString *_fromEmail;
+}
+
+- (NSString *)dataForKey:(FIRActionDataKey)key{
+ switch (key) {
+ case FIRActionCodeEmailKey:
+ return _email;
+ case FIRActionCodeFromEmailKey:
+ return _fromEmail;
+ }
+}
+
+- (instancetype)initWithOperation:(FIRActionCodeOperation)operation
+ email:(NSString *)email
+ newEmail:(nullable NSString *)newEmail {
+ self = [super init];
+ if (self) {
+ _operation = operation;
+ if (newEmail) {
+ _email = [newEmail copy];
+ _fromEmail = [email copy];
+ } else {
+ _email = [email copy];
+ }
+ }
+ return self;
+}
+
+/** @fn actionCodeOperationForRequestType:
+ @brief Returns the corresponding operation type per provided request type string.
+ @param requestType Request type returned in in the server response.
+ @return The corresponding FIRActionCodeOperation for the supplied request type.
+ */
++ (FIRActionCodeOperation)actionCodeOperationForRequestType:(NSString *)requestType {
+ if ([requestType isEqualToString:kPasswordResetRequestType]) {
+ return FIRActionCodeOperationPasswordReset;
+ }
+ if ([requestType isEqualToString:kVerifyEmailRequestType]) {
+ return FIRActionCodeOperationVerifyEmail;
+ }
+ return FIRActionCodeOperationUnknown;
+}
+
+@end
+
+#pragma mark - FIRAuth
+
+@interface FIRAuth () <FIRAuthAppDelegateHandler>
+
+/** @property firebaseAppId
+ @brief The Firebase app ID.
+ */
+@property(nonatomic, copy, readonly) NSString *firebaseAppId;
+
+/** @fn initWithApp:
+ @brief Creates a @c FIRAuth instance associated with the provided @c FIRApp instance.
+ @param app The application to associate the auth instance with.
+ */
+- (instancetype)initWithApp:(FIRApp *)app;
+
+@end
+
+@implementation FIRAuth {
+ /** @var _firebaseAppName
+ @brief The Firebase app name.
+ */
+ NSString *_firebaseAppName;
+
+ /** @var _listenerHandles
+ @brief Handles returned from @c NSNotificationCenter for blocks which are "auth state did
+ change" notification listeners.
+ @remarks Mutations should occur within a @syncronized(self) context.
+ */
+ NSMutableArray<FIRAuthStateDidChangeListenerHandle> *_listenerHandles;
+
+ /** @var _keychain
+ @brief The keychain service.
+ */
+ FIRAuthKeychain *_keychain;
+
+ /** @var _autoRefreshTokens
+ @brief This flag denotes whether or not tokens should be automatically refreshed.
+ @remarks Will only be set to @YES if the another Firebase service is included (additionally to
+ Firebase Auth).
+ */
+ BOOL _autoRefreshTokens;
+
+ /** @var _autoRefreshScheduled
+ @brief Whether or not token auto-refresh is currently scheduled.
+ */
+ BOOL _autoRefreshScheduled;
+
+ /** @var _isAppInBackground
+ @brief A flag that is set to YES if the app is put in the background and no when the app is
+ returned to the foreground.
+ */
+ BOOL _isAppInBackground;
+
+ /** @var _applicationDidBecomeActiveObserver
+ @brief An opaque object to act as the observer for UIApplicationDidBecomeActiveNotification.
+ */
+ id<NSObject> _applicationDidBecomeActiveObserver;
+
+ /** @var _applicationDidBecomeActiveObserver
+ @brief An opaque object to act as the observer for
+ UIApplicationDidEnterBackgroundNotification.
+ */
+ id<NSObject> _applicationDidEnterBackgroundObserver;
+}
+
++ (void)load {
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ gKeychainServiceNameForAppName = [[NSMutableDictionary alloc] init];
+
+ NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
+
+ // Ensures the @c FIRAuth instance for a given app gets loaded as soon as the app is ready.
+ [defaultCenter addObserverForName:kFIRAppReadyToConfigureSDKNotification
+ object:[FIRApp class]
+ queue:nil
+ usingBlock:^(NSNotification *notification) {
+ [FIRAuth authWithApp:[FIRApp appNamed:notification.userInfo[kFIRAppNameKey]]];
+ }];
+ // Ensures the saved user is cleared when the app is deleted.
+ [defaultCenter addObserverForName:kFIRAppDeleteNotification
+ object:[FIRApp class]
+ queue:nil
+ usingBlock:^(NSNotification *notification) {
+ dispatch_async(FIRAuthGlobalWorkQueue(), ^{
+ // This doesn't stop any request already issued, see b/27704535 .
+ NSString *appName = notification.userInfo[kFIRAppNameKey];
+ NSString *keychainServiceName = [FIRAuth keychainServiceNameForAppName:appName];
+ if (keychainServiceName) {
+ [self deleteKeychainServiceNameForAppName:appName];
+ FIRAuthKeychain *keychain = [[FIRAuthKeychain alloc] initWithService:keychainServiceName];
+ NSString *userKey = [NSString stringWithFormat:kUserKey, appName];
+ [keychain removeDataForKey:userKey error:NULL];
+ }
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [[NSNotificationCenter defaultCenter]
+ postNotificationName:FIRAuthStateDidChangeNotification
+ object:nil];
+ });
+ });
+ }];
+ });
+}
+
++ (FIRAuth *)auth {
+ FIRApp *defaultApp = [FIRApp defaultApp];
+ if (!defaultApp) {
+ [NSException raise:NSInternalInconsistencyException
+ format:@"The default FIRApp instance must be configured before the default FIRAuth"
+ @"instance can be initialized. One way to ensure that is to call "
+ @"`[FIRApp configure];` is called in "
+ @"`application:didFinishLaunchingWithOptions:`."];
+ }
+ return [self authWithApp:defaultApp];
+}
+
++ (FIRAuth *)authWithApp:(FIRApp *)app {
+ return [FIRAppAssociationRegistration registeredObjectWithHost:app
+ key:NSStringFromClass(self)
+ creationBlock:^FIRAuth *_Nullable() {
+ return [[FIRAuth alloc] initWithApp:app];
+ }];
+}
+
+- (instancetype)initWithApp:(FIRApp *)app {
+ [FIRAuth setKeychainServiceNameForApp:app];
+ self = [self initWithAPIKey:app.options.APIKey appName:app.name];
+ if (self) {
+ _app = app;
+ __weak FIRAuth *weakSelf = self;
+ app.getTokenImplementation = ^(BOOL forceRefresh, FIRTokenCallback callback) {
+ dispatch_async(FIRAuthGlobalWorkQueue(), ^{
+ FIRAuth *strongSelf = weakSelf;
+ if (strongSelf && !strongSelf->_autoRefreshTokens) {
+ FIRLogInfo(kFIRLoggerAuth, @"I-AUT000002", @"Token auto-refresh enabled.");
+ strongSelf->_autoRefreshTokens = YES;
+ strongSelf->_applicationDidBecomeActiveObserver = [[NSNotificationCenter defaultCenter]
+ addObserverForName:UIApplicationDidBecomeActiveNotification
+ object:nil
+ queue:nil
+ usingBlock:^(NSNotification *notification) {
+ FIRAuth *strongSelf = weakSelf;
+ if (strongSelf) {
+ strongSelf->_isAppInBackground = NO;
+ if (!strongSelf->_autoRefreshScheduled) {
+ [weakSelf scheduleAutoTokenRefresh];
+ }
+ }
+ }];
+ strongSelf->_applicationDidEnterBackgroundObserver = [[NSNotificationCenter defaultCenter]
+ addObserverForName:UIApplicationDidEnterBackgroundNotification
+ object:nil
+ queue:nil
+ usingBlock:^(NSNotification *notification) {
+ FIRAuth *strongSelf = weakSelf;
+ if (strongSelf) {
+ strongSelf->_isAppInBackground = YES;
+ }
+ }];
+ }
+ if (!strongSelf.currentUser) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ callback(nil, nil);
+ });
+ return;
+ }
+ [strongSelf.currentUser internalGetTokenForcingRefresh:forceRefresh
+ callback:^(NSString *_Nullable token,
+ NSError *_Nullable error) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ callback(token, error);
+ });
+ }];
+ });
+ };
+ app.getUIDImplementation = ^NSString *_Nullable() {
+ __block NSString *uid;
+ dispatch_sync(FIRAuthGlobalWorkQueue(), ^{
+ uid = [weakSelf getUID];
+ });
+ return uid;
+ };
+ }
+ return self;
+}
+
+- (instancetype)initWithAPIKey:(NSString *)APIKey appName:(NSString *)appName {
+ self = [super init];
+ if (self) {
+ _listenerHandles = [NSMutableArray array];
+ _APIKey = [APIKey copy];
+ _firebaseAppName = [appName copy];
+ NSString *keychainServiceName = [FIRAuth keychainServiceNameForAppName:appName];
+ if (keychainServiceName) {
+ _keychain = [[FIRAuthKeychain alloc] initWithService:keychainServiceName];
+ }
+ // Load current user from keychain.
+ FIRUser *user;
+ NSError *error;
+ if ([self getUser:&user error:&error]) {
+ [self updateCurrentUser:user byForce:NO savingToDisk:NO error:&error];
+ } else {
+ FIRLogError(kFIRLoggerAuth, @"I-AUT000001",
+ @"Error loading saved user when starting up: %@", error);
+ }
+ // Initialize for phone number auth.
+ _tokenManager =
+ [[FIRAuthAPNSTokenManager alloc] initWithApplication:[UIApplication sharedApplication]];
+ _appCredentialManager = [[FIRAuthAppCredentialManager alloc] initWithKeychain:_keychain];
+ _notificationManager =
+ [[FIRAuthNotificationManager alloc] initWithApplication:[UIApplication sharedApplication]
+ appCredentialManager:_appCredentialManager];
+ [[FIRAuthAppDelegateProxy sharedInstance] addHandler:self];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ @synchronized (self) {
+ NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
+ while (_listenerHandles.count != 0) {
+ FIRAuthStateDidChangeListenerHandle handleToRemove = _listenerHandles.lastObject;
+ [defaultCenter removeObserver:handleToRemove];
+ [_listenerHandles removeLastObject];
+ }
+ [defaultCenter removeObserver:_applicationDidBecomeActiveObserver
+ name:UIApplicationDidBecomeActiveNotification
+ object:nil];
+ [defaultCenter removeObserver:_applicationDidEnterBackgroundObserver
+ name:UIApplicationDidEnterBackgroundNotification
+ object:nil];
+ }
+}
+
+#pragma mark - Public API
+
+- (void)fetchProvidersForEmail:(NSString *)email
+ completion:(FIRProviderQueryCallback)completion {
+ dispatch_async(FIRAuthGlobalWorkQueue(), ^{
+ FIRCreateAuthURIRequest *request =
+ [[FIRCreateAuthURIRequest alloc] initWithIdentifier:email
+ continueURI:@"http://www.google.com/"
+ APIKey:_APIKey];
+ [FIRAuthBackend createAuthURI:request callback:^(FIRCreateAuthURIResponse *_Nullable response,
+ NSError *_Nullable error) {
+ if (completion) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ completion(response.allProviders, error);
+ });
+ }
+ }];
+ });
+}
+
+- (void)signInWithEmail:(NSString *)email
+ password:(NSString *)password
+ completion:(FIRAuthResultCallback)completion {
+ dispatch_async(FIRAuthGlobalWorkQueue(), ^{
+ [self signInWithEmail:email
+ password:password
+ callback:[self signInFlowAuthResultCallbackByDecoratingCallback:completion]];
+ });
+}
+
+/** @fn signInWithEmail:password:callback:
+ @brief Signs in using an email address and password.
+ @param email The user's email address.
+ @param password The user's password.
+ @param callback A block which is invoked when the sign in finishes (or is cancelled.) Invoked
+ asynchronously on the global auth work queue in the future.
+ @remarks This is the internal counterpart of this method, which uses a callback that does not
+ update the current user.
+ */
+- (void)signInWithEmail:(NSString *)email
+ password:(NSString *)password
+ callback:(FIRAuthResultCallback)callback {
+ FIRVerifyPasswordRequest *request =
+ [[FIRVerifyPasswordRequest alloc] initWithEmail:email password:password APIKey:_APIKey];
+
+ if (![request.password length]) {
+ callback(nil, [FIRAuthErrorUtils wrongPasswordErrorWithMessage:nil]);
+ return;
+ }
+ [FIRAuthBackend verifyPassword:request
+ callback:^(FIRVerifyPasswordResponse *_Nullable response,
+ NSError *_Nullable error) {
+ if (error) {
+ callback(nil, error);
+ return;
+ }
+ [self completeSignInWithAccessToken:response.IDToken
+ accessTokenExpirationDate:response.approximateExpirationDate
+ refreshToken:response.refreshToken
+ anonymous:NO
+ callback:callback];
+ }];
+}
+
+- (void)signInWithCredential:(FIRAuthCredential *)credential
+ completion:(FIRAuthResultCallback)completion {
+ dispatch_async(FIRAuthGlobalWorkQueue(), ^{
+ FIRAuthResultCallback callback =
+ [self signInFlowAuthResultCallbackByDecoratingCallback:completion];
+ [self internalSignInWithCredential:credential callback:callback];
+ });
+}
+
+- (void)signInAndRetrieveDataWithCredential:(FIRAuthCredential *)credential
+ completion:(nullable FIRAuthDataResultCallback)completion {
+ dispatch_async(FIRAuthGlobalWorkQueue(), ^{
+ FIRAuthDataResultCallback callback =
+ [self signInFlowAuthDataResultCallbackByDecoratingCallback:completion];
+ [self internalSignInAndRetrieveDataWithCredential:credential
+ isReauthentication:NO
+ callback:callback];
+ });
+}
+
+- (void)internalSignInWithCredential:(FIRAuthCredential *)credential
+ callback:(FIRAuthResultCallback)callback {
+ [self internalSignInAndRetrieveDataWithCredential:credential
+ isReauthentication:NO
+ callback:^(FIRAuthDataResult *_Nullable authResult,
+ NSError *_Nullable error) {
+ callback(authResult.user, error);
+ }];
+}
+
+- (void)internalSignInAndRetrieveDataWithCredential:(FIRAuthCredential *)credential
+ isReauthentication:(BOOL)isReauthentication
+ callback:(nullable FIRAuthDataResultCallback)callback {
+ if ([credential isKindOfClass:[FIREmailPasswordAuthCredential class]]) {
+ // Special case for email/password credentials:
+ FIREmailPasswordAuthCredential *emailPasswordCredential =
+ (FIREmailPasswordAuthCredential *)credential;
+ [self signInWithEmail:emailPasswordCredential.email
+ password:emailPasswordCredential.password
+ callback:^(FIRUser *_Nullable user, NSError *_Nullable error) {
+ if (callback) {
+ FIRAuthDataResult *result = user ?
+ [[FIRAuthDataResult alloc] initWithUser:user additionalUserInfo:nil] : nil;
+ callback(result, error);
+ }
+ }];
+ return;
+ }
+
+ if ([credential isKindOfClass:[FIRPhoneAuthCredential class]]) {
+ // Special case for phone auth credential
+ FIRPhoneAuthCredential *phoneCredential = (FIRPhoneAuthCredential *)credential;
+ [self signInWithPhoneCredential:phoneCredential callback:^(FIRUser *_Nullable user,
+ NSError *_Nullable error) {
+ if (callback) {
+ FIRAuthDataResult *result = user ?
+ [[FIRAuthDataResult alloc] initWithUser:user additionalUserInfo:nil] : nil;
+ callback(result, error);
+ }
+ }];
+ return;
+ }
+
+ FIRVerifyAssertionRequest *request =
+ [[FIRVerifyAssertionRequest alloc] initWithAPIKey:_APIKey providerID:credential.provider];
+ request.autoCreate = !isReauthentication;
+ [credential prepareVerifyAssertionRequest:request];
+ [FIRAuthBackend verifyAssertion:request
+ callback:^(FIRVerifyAssertionResponse *response, NSError *error) {
+ if (error) {
+ if (callback) {
+ callback(nil, error);
+ }
+ return;
+ }
+
+ if (response.needConfirmation) {
+ if (callback) {
+ NSString *email = response.email;
+ callback(nil, [FIRAuthErrorUtils accountExistsWithDifferentCredentialErrorWithEmail:email]);
+ }
+ return;
+ }
+
+ if (!response.providerID.length) {
+ if (callback) {
+ callback(nil, [FIRAuthErrorUtils unexpectedResponseWithDeserializedResponse:response]);
+ }
+ return;
+ }
+ [self completeSignInWithAccessToken:response.IDToken
+ accessTokenExpirationDate:response.approximateExpirationDate
+ refreshToken:response.refreshToken
+ anonymous:NO
+ callback:^(FIRUser *_Nullable user, NSError *_Nullable error) {
+ if (callback) {
+ FIRAdditionalUserInfo *additionalUserInfo =
+ [FIRAdditionalUserInfo userInfoWithVerifyAssertionResponse:response];
+ FIRAuthDataResult *result = user ?
+ [[FIRAuthDataResult alloc] initWithUser:user
+ additionalUserInfo:additionalUserInfo] : nil;
+ callback(result, error);
+ }
+ }];
+ }];
+}
+
+- (void)signInWithCredential:(FIRAuthCredential *)credential
+ callback:(FIRAuthResultCallback)callback {
+ [self signInAndRetrieveDataWithCredential:credential
+ completion:^(FIRAuthDataResult *_Nullable authResult,
+ NSError *_Nullable error) {
+ callback(authResult.user, error);
+ }];
+}
+
+- (void)signInAnonymouslyWithCompletion:(FIRAuthResultCallback)completion {
+ dispatch_async(FIRAuthGlobalWorkQueue(), ^{
+ FIRAuthResultCallback decoratedCallback =
+ [self signInFlowAuthResultCallbackByDecoratingCallback:completion];
+ if (_currentUser.anonymous) {
+ decoratedCallback(_currentUser, nil);
+ return;
+ }
+ FIRSignUpNewUserRequest *request = [[FIRSignUpNewUserRequest alloc] initWithAPIKey:_APIKey];
+ [FIRAuthBackend signUpNewUser:request
+ callback:^(FIRSignUpNewUserResponse *_Nullable response,
+ NSError *_Nullable error) {
+ if (error) {
+ decoratedCallback(nil, error);
+ return;
+ }
+ [self completeSignInWithAccessToken:response.IDToken
+ accessTokenExpirationDate:response.approximateExpirationDate
+ refreshToken:response.refreshToken
+ anonymous:YES
+ callback:decoratedCallback];
+ }];
+ });
+}
+
+- (void)signInWithCustomToken:(NSString *)token
+ completion:(nullable FIRAuthResultCallback)completion {
+ dispatch_async(FIRAuthGlobalWorkQueue(), ^{
+ FIRAuthResultCallback decoratedCallback =
+ [self signInFlowAuthResultCallbackByDecoratingCallback:completion];
+ FIRVerifyCustomTokenRequest *request =
+ [[FIRVerifyCustomTokenRequest alloc] initWithToken:token APIKey:_APIKey];
+ [FIRAuthBackend verifyCustomToken:request
+ callback:^(FIRVerifyCustomTokenResponse *_Nullable response,
+ NSError *_Nullable error) {
+ if (error) {
+ decoratedCallback(nil, error);
+ return;
+ }
+ [self completeSignInWithAccessToken:response.IDToken
+ accessTokenExpirationDate:response.approximateExpirationDate
+ refreshToken:response.refreshToken
+ anonymous:NO
+ callback:decoratedCallback];
+ }];
+ });
+}
+
+- (void)createUserWithEmail:(NSString *)email
+ password:(NSString *)password
+ completion:(nullable FIRAuthResultCallback)completion {
+ dispatch_async(FIRAuthGlobalWorkQueue(), ^{
+ FIRAuthResultCallback decoratedCallback =
+ [self signInFlowAuthResultCallbackByDecoratingCallback:completion];
+ FIRSignUpNewUserRequest *request = [[FIRSignUpNewUserRequest alloc] initWithAPIKey:_APIKey
+ email:email
+ password:password
+ displayName:nil];
+ if (![request.password length]) {
+ decoratedCallback(nil, [FIRAuthErrorUtils
+ weakPasswordErrorWithServerResponseReason:kMissingPasswordReason]);
+ return;
+ }
+ [FIRAuthBackend signUpNewUser:request
+ callback:^(FIRSignUpNewUserResponse *_Nullable response,
+ NSError *_Nullable error) {
+ if (error) {
+ decoratedCallback(nil, error);
+ return;
+ }
+ [self completeSignInWithAccessToken:response.IDToken
+ accessTokenExpirationDate:response.approximateExpirationDate
+ refreshToken:response.refreshToken
+ anonymous:NO
+ callback:decoratedCallback];
+ }];
+ });
+}
+
+- (void)confirmPasswordResetWithCode:(NSString *)code
+ newPassword:(NSString *)newPassword
+ completion:(FIRConfirmPasswordResetCallback)completion {
+ dispatch_async(FIRAuthGlobalWorkQueue(), ^{
+ FIRResetPasswordRequest *request =
+ [[FIRResetPasswordRequest alloc] initWithAPIKey:_APIKey
+ oobCode:code
+ newPassword:newPassword];
+ [FIRAuthBackend resetPassword:request callback:^(FIRResetPasswordResponse *_Nullable response,
+ NSError *_Nullable error) {
+ if (completion) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ if (error) {
+ completion(error);
+ return;
+ }
+ completion(nil);
+ });
+ }
+ }];
+ });
+}
+
+- (void)checkActionCode:(NSString *)code completion:(FIRCheckActionCodeCallBack)completion {
+ dispatch_async(FIRAuthGlobalWorkQueue(), ^ {
+ FIRResetPasswordRequest *request =
+ [[FIRResetPasswordRequest alloc] initWithAPIKey:_APIKey
+ oobCode:code
+ newPassword:nil];
+ [FIRAuthBackend resetPassword:request callback:^(FIRResetPasswordResponse *_Nullable response,
+ NSError *_Nullable error) {
+ if (completion) {
+ if (error) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ completion(nil, error);
+ });
+ return;
+ }
+ FIRActionCodeOperation operation =
+ [FIRActionCodeInfo actionCodeOperationForRequestType:response.requestType];
+ FIRActionCodeInfo *actionCodeInfo =
+ [[FIRActionCodeInfo alloc] initWithOperation:operation
+ email:response.email
+ newEmail:response.verifiedEmail];
+ dispatch_async(dispatch_get_main_queue(), ^{
+ completion(actionCodeInfo, nil);
+ });
+ }
+ }];
+ });
+}
+
+- (void)verifyPasswordResetCode:(NSString *)code
+ completion:(FIRVerifyPasswordResetCodeCallback)completion {
+ [self checkActionCode:code completion:^(FIRActionCodeInfo *_Nullable info,
+ NSError *_Nullable error) {
+ if (completion) {
+ if (error) {
+ completion(nil, error);
+ return;
+ }
+ completion([info dataForKey:FIRActionCodeEmailKey], nil);
+ }
+ }];
+}
+
+- (void)applyActionCode:(NSString *)code completion:(FIRApplyActionCodeCallback)completion {
+ dispatch_async(FIRAuthGlobalWorkQueue(), ^ {
+ FIRSetAccountInfoRequest *request = [[FIRSetAccountInfoRequest alloc]initWithAPIKey:_APIKey];
+ request.OOBCode = code;
+ [FIRAuthBackend setAccountInfo:request callback:^(FIRSetAccountInfoResponse *_Nullable response,
+ NSError *_Nullable error) {
+ if (completion) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ completion(error);
+ });
+ }
+ }];
+ });
+}
+
+- (void)sendPasswordResetWithEmail:(NSString *)email
+ completion:(nullable FIRSendPasswordResetCallback)completion {
+ dispatch_async(FIRAuthGlobalWorkQueue(), ^{
+ if (!email) {
+ [FIRAuthExceptionUtils raiseInvalidParameterExceptionWithReason:kEmailInvalidParameterReason];
+ }
+ FIRGetOOBConfirmationCodeRequest *request =
+ [FIRGetOOBConfirmationCodeRequest passwordResetRequestWithEmail:email APIKey:_APIKey];
+ [FIRAuthBackend getOOBConfirmationCode:request
+ callback:^(FIRGetOOBConfirmationCodeResponse *_Nullable response,
+ NSError *_Nullable error) {
+ if (completion) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ completion(error);
+ });
+ }
+ }];
+ });
+}
+
+- (BOOL)signOut:(NSError *_Nullable *_Nullable)error {
+ __block BOOL result = YES;
+ dispatch_sync(FIRAuthGlobalWorkQueue(), ^{
+ if (!_currentUser) {
+ return;
+ }
+ result = [self updateCurrentUser:nil byForce:NO savingToDisk:YES error:error];
+ });
+ return result;
+}
+
+- (BOOL)signOutByForceWithUserID:(NSString *)userID error:(NSError *_Nullable *_Nullable)error {
+ if (_currentUser.uid != userID) {
+ return YES;
+ }
+ return [self updateCurrentUser:nil byForce:YES savingToDisk:YES error:error];
+}
+
+- (FIRAuthStateDidChangeListenerHandle)addAuthStateDidChangeListener:
+ (FIRAuthStateDidChangeListenerBlock)listener {
+ __block BOOL firstInvocation = YES;
+ __block NSString *previousUserID;
+ return [self addIDTokenDidChangeListener:^(FIRAuth *_Nonnull auth, FIRUser *_Nullable user) {
+ BOOL shouldCallListener = firstInvocation ||
+ !(previousUserID == user.uid || [previousUserID isEqualToString:user.uid]);
+ firstInvocation = NO;
+ previousUserID = [user.uid copy];
+ if (shouldCallListener) {
+ listener(auth, user);
+ }
+ }];
+}
+
+- (void)removeAuthStateDidChangeListener:(FIRAuthStateDidChangeListenerHandle)listenerHandle {
+ [self removeIDTokenDidChangeListener:listenerHandle];
+}
+
+- (FIRIDTokenDidChangeListenerHandle)addIDTokenDidChangeListener:
+ (FIRIDTokenDidChangeListenerBlock)listener {
+ if (!listener) {
+ [NSException raise:NSInvalidArgumentException format:@"listener must not be nil."];
+ return nil;
+ }
+ FIRAuthStateDidChangeListenerHandle handle;
+ NSNotificationCenter *notifications = [NSNotificationCenter defaultCenter];
+ handle = [notifications addObserverForName:FIRAuthStateDidChangeNotification
+ object:self
+ queue:[NSOperationQueue mainQueue]
+ usingBlock:^(NSNotification *_Nonnull notification) {
+ FIRAuth *auth = notification.object;
+ listener(auth, auth.currentUser);
+ }];
+ @synchronized (self) {
+ [_listenerHandles addObject:handle];
+ }
+ dispatch_async(dispatch_get_main_queue(), ^{
+ listener(self, self.currentUser);
+ });
+ return handle;
+}
+
+- (void)removeIDTokenDidChangeListener:(FIRIDTokenDidChangeListenerHandle)listenerHandle {
+ [[NSNotificationCenter defaultCenter] removeObserver:listenerHandle];
+ @synchronized (self) {
+ [_listenerHandles removeObject:listenerHandle];
+ }
+}
+
+- (NSData *)APNStoken {
+ __block NSData *result = nil;
+ dispatch_sync(FIRAuthGlobalWorkQueue(), ^{
+ result = _tokenManager.token.data;
+ });
+ return result;
+}
+
+- (void)setAPNSToken:(NSData *)APNSToken {
+ [self setAPNSToken:APNSToken type:FIRAuthAPNSTokenTypeUnknown];
+}
+
+- (void)setAPNSToken:(NSData *)token type:(FIRAuthAPNSTokenType)type {
+ dispatch_sync(FIRAuthGlobalWorkQueue(), ^{
+ _tokenManager.token = [[FIRAuthAPNSToken alloc] initWithData:token type:type];
+ });
+}
+
+- (BOOL)canHandleNotification:(NSDictionary *)userInfo {
+ __block BOOL result = NO;
+ dispatch_sync(FIRAuthGlobalWorkQueue(), ^{
+ result = [_notificationManager canHandleNotification:userInfo];
+ });
+ return result;
+}
+
+#pragma mark - Internal Methods
+
+/** @fn signInWithPhoneCredential:callback:
+ @brief Signs in using a phone credential.
+ @param credential The Phone Auth credential used to sign in.
+ @param callback A block which is invoked when the sign in finishes (or is cancelled.) Invoked
+ asynchronously on the global auth work queue in the future.
+ */
+- (void)signInWithPhoneCredential:(FIRPhoneAuthCredential *)credential
+ callback:(FIRAuthResultCallback)callback {
+ if (credential.temporaryProof.length && credential.phoneNumber.length) {
+ FIRVerifyPhoneNumberRequest *request =
+ [[FIRVerifyPhoneNumberRequest alloc] initWithTemporaryProof:credential.temporaryProof
+ phoneNumber:credential.phoneNumber
+ APIKey:_APIKey];
+ [self phoneNumberSignInWithRequest:request callback:callback];
+ return;
+ }
+
+ if (!credential.verificationID.length) {
+ callback(nil, [FIRAuthErrorUtils missingVerificationIDErrorWithMessage:nil]);
+ return;
+ }
+ if (!credential.verificationCode.length) {
+ callback(nil, [FIRAuthErrorUtils missingVerificationCodeErrorWithMessage:nil]);
+ return;
+ }
+ FIRVerifyPhoneNumberRequest *request =
+ [[FIRVerifyPhoneNumberRequest alloc]initWithVerificationID:credential.verificationID
+ verificationCode:credential.verificationCode
+ APIKey:_APIKey];
+ [self phoneNumberSignInWithRequest:request callback:callback];
+}
+
+
+/** @fn phoneNumberSignInWithVerificationID:pasverificationCodesword:callback:
+ @brief Signs in using a FIRVerifyPhoneNumberRequest object.
+ @param request THe FIRVerifyPhoneNumberRequest request object.
+ @param callback A block which is invoked when the sign in finishes (or is cancelled.) Invoked
+ asynchronously on the global auth work queue in the future.
+ */
+- (void)phoneNumberSignInWithRequest:(FIRVerifyPhoneNumberRequest *)request
+ callback:(FIRAuthResultCallback)callback {
+ [FIRAuthBackend verifyPhoneNumber:request
+ callback:^(FIRVerifyPhoneNumberResponse *_Nullable response,
+ NSError *_Nullable error) {
+ if (error) {
+ callback(nil, error);
+ return;
+ }
+ [self completeSignInWithAccessToken:response.IDToken
+ accessTokenExpirationDate:response.approximateExpirationDate
+ refreshToken:response.refreshToken
+ anonymous:NO
+ callback:callback];
+ }];
+}
+
+- (void)notifyListenersOfAuthStateChangeWithUser:(FIRUser *)user token:(NSString *)token {
+ if (user && _autoRefreshTokens) {
+ // Shedule new refresh task after successful attempt.
+ [self scheduleAutoTokenRefresh];
+ }
+ if (user == _currentUser) {
+ NSMutableDictionary *internalNotificationParameters = [NSMutableDictionary dictionary];
+ if (token.length) {
+ internalNotificationParameters[FIRAuthStateDidChangeInternalNotificationTokenKey] = token;
+ }
+ NSNotificationCenter *notifications = [NSNotificationCenter defaultCenter];
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [notifications postNotificationName:FIRAuthStateDidChangeInternalNotification
+ object:self
+ userInfo:internalNotificationParameters];
+ [notifications postNotificationName:FIRAuthStateDidChangeNotification
+ object:self];
+ });
+ }
+}
+
+- (BOOL)updateKeychainWithUser:(FIRUser *)user error:(NSError *_Nullable *_Nullable)error {
+ if (user == _currentUser) {
+ return [self saveUser:user error:error];
+ }
+ // No-op if the user is no longer signed in. This is not considered an error as we don't check
+ // whether the user is still current on other callbacks of user operations either.
+ return YES;
+}
+
+/** @fn setKeychainServiceNameForApp
+ @brief Sets the keychain service name global data for the particular app.
+ @param app The Firebase app to set keychain service name for.
+ */
++ (void)setKeychainServiceNameForApp:(FIRApp *)app {
+ @synchronized (self) {
+ gKeychainServiceNameForAppName[app.name] =
+ [@"firebase_auth_" stringByAppendingString:app.options.googleAppID];
+ }
+}
+
+/** @fn keychainServiceNameForAppName:
+ @brief Gets the keychain service name global data for the particular app by name.
+ @param appName The name of the Firebase app to get keychain service name for.
+ */
++ (NSString *)keychainServiceNameForAppName:(NSString *)appName {
+ @synchronized (self) {
+ return gKeychainServiceNameForAppName[appName];
+ }
+}
+
+/** @fn deleteKeychainServiceNameForAppName:
+ @brief Deletes the keychain service name global data for the particular app by name.
+ @param appName The name of the Firebase app to delete keychain service name for.
+ */
++ (void)deleteKeychainServiceNameForAppName:(NSString *)appName {
+ @synchronized (self) {
+ [gKeychainServiceNameForAppName removeObjectForKey:appName];
+ }
+}
+
+/** @fn scheduleAutoTokenRefreshWithDelay:
+ @brief Schedules a task to automatically refresh tokens on the current user. The token refresh
+ is scheduled 5 minutes before the scheduled expiration time.
+ @remarks If the token expires in less than 5 minutes, schedule the token refresh immediately.
+ */
+- (void)scheduleAutoTokenRefresh {
+ NSTimeInterval tokenExpirationInterval =
+ [_currentUser.accessTokenExpirationDate timeIntervalSinceNow] - kTokenRefreshHeadStart;
+ [self scheduleAutoTokenRefreshWithDelay:MAX(tokenExpirationInterval, 0) retry:NO];
+}
+
+/** @fn scheduleAutoTokenRefreshWithDelay:
+ @brief Schedules a task to automatically refresh tokens on the current user.
+ @param delay The delay in seconds after which the token refresh task should be scheduled to be
+ executed.
+ @param retry Flag to determine whether the invocation is a retry attempt or not.
+ */
+- (void)scheduleAutoTokenRefreshWithDelay:(NSTimeInterval)delay retry:(BOOL)retry {
+ NSString *accessToken = _currentUser.rawAccessToken;
+ if (!accessToken) {
+ return;
+ }
+ if (retry) {
+ FIRLogNotice(kFIRLoggerAuth, @"I-AUT000003",
+ @"Token auto-refresh re-scheduled in %02d:%02d "
+ @"because of error on previous refresh attempt.",
+ (int)ceil(delay) / 60, (int)ceil(delay) % 60);
+ } else {
+ FIRLogInfo(kFIRLoggerAuth, @"I-AUT000004",
+ @"Token auto-refresh scheduled in %02d:%02d for the new token.",
+ (int)ceil(delay) / 60, (int)ceil(delay) % 60);
+ }
+ _autoRefreshScheduled = YES;
+ __weak FIRAuth *weakSelf = self;
+ [[FIRAuthDispatcher sharedInstance] dispatchAfterDelay:delay
+ queue:FIRAuthGlobalWorkQueue()
+ task:^(void) {
+ FIRAuth *strongSelf = weakSelf;
+ if (!strongSelf) {
+ return;
+ }
+ if (![strongSelf->_currentUser.rawAccessToken isEqualToString:accessToken]) {
+ // Another auto refresh must have been scheduled, so keep _autoRefreshScheduled unchanged.
+ return;
+ }
+ strongSelf->_autoRefreshScheduled = NO;
+ if (strongSelf->_isAppInBackground) {
+ return;
+ }
+ NSString *uid = strongSelf->_currentUser.uid;
+ [strongSelf->_currentUser internalGetTokenForcingRefresh:YES
+ callback:^(NSString *_Nullable token,
+ NSError *_Nullable error) {
+ if (![strongSelf->_currentUser.uid isEqualToString:uid]) {
+ return;
+ }
+ // If the error is an invalid token, sign the user out.
+ if (error.code == FIRAuthErrorCodeInvalidUserToken) {
+ FIRLogWarning(kFIRLoggerAuth, @"I-AUT000005",
+ @"Invalid refresh token detected, user is automatically signed out.");
+ [strongSelf signOutByForceWithUserID:uid error:nil];
+ return;
+ }
+ if (error) {
+ // Kicks off exponential back off logic to retry failed attempt. Starts with one minute
+ // delay (60 seconds) if this is the first failed attempt.
+ NSTimeInterval rescheduleDelay;
+ if (retry) {
+ rescheduleDelay = MIN(delay * 2, kMaxWaitTimeForBackoff);
+ } else {
+ rescheduleDelay = 60;
+ }
+ [strongSelf scheduleAutoTokenRefreshWithDelay:rescheduleDelay retry:YES];
+ }
+ }];
+ }];
+}
+
+#pragma mark -
+
+/** @fn completeSignInWithTokenService:callback:
+ @brief Completes a sign-in flow once we have access and refresh tokens for the user.
+ @param accessToken The STS access token.
+ @param accessTokenExpirationDate The approximate expiration date of the access token.
+ @param refreshToken The STS refresh token.
+ @param anonymous Whether or not the user is anonymous.
+ @param callback Called when the user has been signed in or when an error occurred. Invoked
+ asynchronously on the global auth work queue in the future.
+ */
+- (void)completeSignInWithAccessToken:(NSString *)accessToken
+ accessTokenExpirationDate:(NSDate *)accessTokenExpirationDate
+ refreshToken:(NSString *)refreshToken
+ anonymous:(BOOL)anonymous
+ callback:(FIRAuthResultCallback)callback {
+ [FIRUser retrieveUserWithAPIKey:_APIKey
+ accessToken:accessToken
+ accessTokenExpirationDate:accessTokenExpirationDate
+ refreshToken:refreshToken
+ anonymous:anonymous
+ callback:callback];
+}
+
+/** @fn signInFlowAuthResultCallbackByDecoratingCallback:
+ @brief Creates a FIRAuthResultCallback block which wraps another FIRAuthResultCallback; trying
+ to update the current user before forwarding it's invocations along to a subject block
+ @param callback Called when the user has been updated or when an error has occurred. Invoked
+ asynchronously on the main thread in the future.
+ @return Returns a block that updates the current user.
+ @remarks Typically invoked as part of the complete sign-in flow. For any other uses please
+ consider alternative ways of updating the current user.
+*/
+- (FIRAuthResultCallback)signInFlowAuthResultCallbackByDecoratingCallback:
+ (nullable FIRAuthResultCallback)callback {
+ return ^(FIRUser *_Nullable user, NSError *_Nullable error) {
+ if (error) {
+ if (callback) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ callback(nil, error);
+ });
+ }
+ return;
+ }
+ if (![self updateCurrentUser:user byForce:NO savingToDisk:YES error:&error]) {
+ if (callback) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ callback(nil, error);
+ });
+ }
+ return;
+ }
+ if (callback) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ callback(user, nil);
+ });
+ }
+ };
+}
+
+/** @fn signInFlowAuthDataResultCallbackByDecoratingCallback:
+ @brief Creates a FIRAuthDataResultCallback block which wraps another FIRAuthDataResultCallback;
+ trying to update the current user before forwarding it's invocations along to a subject
+ block.
+ @param callback Called when the user has been updated or when an error has occurred. Invoked
+ asynchronously on the main thread in the future.
+ @return Returns a block that updates the current user.
+ @remarks Typically invoked as part of the complete sign-in flow. For any other uses please
+ consider alternative ways of updating the current user.
+*/
+- (FIRAuthDataResultCallback)signInFlowAuthDataResultCallbackByDecoratingCallback:
+ (nullable FIRAuthDataResultCallback)callback {
+ return ^(FIRAuthDataResult *_Nullable authResult, NSError *_Nullable error) {
+ if (error) {
+ if (callback) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ callback(nil, error);
+ });
+ }
+ return;
+ }
+ if (![self updateCurrentUser:authResult.user byForce:NO savingToDisk:YES error:&error]) {
+ if (callback) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ callback(nil, error);
+ });
+ }
+ return;
+ }
+ if (callback) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ callback(authResult, nil);
+ });
+ }
+ };
+}
+
+#pragma mark - User-Related Methods
+
+/** @fn updateCurrentUser:savingToDisk:
+ @brief Update the current user; initializing the user's internal properties correctly, and
+ optionally saving the user to disk.
+ @remarks This method is called during: sign in and sign out events, as well as during class
+ initialization time. The only time the saveToDisk parameter should be set to NO is during
+ class initialization time because the user was just read from disk.
+ @param user The user to use as the current user (including nil, which is passed at sign out
+ time.)
+ @param saveToDisk Indicates the method should persist the user data to disk.
+ */
+- (BOOL)updateCurrentUser:(FIRUser *)user
+ byForce:(BOOL)force
+ savingToDisk:(BOOL)saveToDisk
+ error:(NSError *_Nullable *_Nullable)error {
+ if (user == _currentUser) {
+ return YES;
+ }
+ BOOL success = YES;
+ if (saveToDisk) {
+ success = [self saveUser:user error:error];
+ }
+ if (success || force) {
+ FIRUser *previousUser = _currentUser;
+ previousUser.auth = nil;
+ _currentUser = user;
+ _currentUser.auth = self;
+ [self notifyListenersOfAuthStateChangeWithUser:user token:user.rawAccessToken];
+ }
+ return success;
+}
+
+/** @fn saveUser:error:
+ @brief Persists user.
+ @param user The user to save.
+ @param error Return value for any error which occurs.
+ @return @YES on success, @NO otherwise.
+ */
+- (BOOL)saveUser:(FIRUser *)user
+ error:(NSError *_Nullable *_Nullable)error {
+ BOOL success;
+ NSString *userKey = [NSString stringWithFormat:kUserKey, _firebaseAppName];
+
+ if (!user) {
+ success = [_keychain removeDataForKey:userKey error:error];
+ } else {
+ // Encode the user object.
+ NSMutableData *archiveData = [NSMutableData data];
+ NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:archiveData];
+ [archiver encodeObject:user forKey:userKey];
+ [archiver finishEncoding];
+
+ // Save the user object's encoded value.
+ success = [_keychain setData:archiveData forKey:userKey error:error];
+ }
+ return success;
+}
+
+/** @fn getUser:error:
+ @brief Retrieves the saved user associated, if one exists, from the keychain.
+ @param outUser An out parameter which is populated with the saved user, if one exists.
+ @param error Return value for any error which occurs.
+ @return YES if the operation was a success (irrespective of whether or not a saved user existed
+ for the given @c firebaseAppId,) NO if an error occurred.
+ */
+- (BOOL)getUser:(FIRUser *_Nullable *)outUser
+ error:(NSError *_Nullable *_Nullable)error {
+ NSString *userKey = [NSString stringWithFormat:kUserKey, _firebaseAppName];
+
+ NSError *keychainError;
+ NSData *encodedUserData = [_keychain dataForKey:userKey error:&keychainError];
+ if (keychainError) {
+ if (error) {
+ *error = keychainError;
+ }
+ return NO;
+ }
+ if (!encodedUserData) {
+ *outUser = nil;
+ return YES;
+ }
+ NSKeyedUnarchiver *unarchiver =
+ [[NSKeyedUnarchiver alloc] initForReadingWithData:encodedUserData];
+ *outUser = [unarchiver decodeObjectOfClass:[FIRUser class] forKey:userKey];
+ return YES;
+}
+
+/** @fn getUID
+ @brief Gets the identifier of the current user, if any.
+ @return The identifier of the current user, or nil if there is no current user.
+ */
+- (nullable NSString *)getUID {
+ return _currentUser.uid;
+}
+
+@end
diff --git a/Firebase/Auth/Source/FIRAuthAPNSToken.m b/Firebase/Auth/Source/FIRAuthAPNSToken.m
new file mode 100644
index 0000000..fc5ee2d
--- /dev/null
+++ b/Firebase/Auth/Source/FIRAuthAPNSToken.m
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "Private/FIRAuthAPNSToken.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@implementation FIRAuthAPNSToken
+
+- (instancetype)initWithData:(NSData *)data type:(FIRAuthAPNSTokenType)type {
+ self = [super init];
+ if (self) {
+ _data = [data copy];
+ _type = type;
+ }
+ return self;
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/FIRAuthAPNSTokenManager.m b/Firebase/Auth/Source/FIRAuthAPNSTokenManager.m
new file mode 100644
index 0000000..9609d86
--- /dev/null
+++ b/Firebase/Auth/Source/FIRAuthAPNSTokenManager.m
@@ -0,0 +1,255 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "Private/FIRAuthAPNSTokenManager.h"
+
+#import "FIRLogger.h"
+#import "Private/FIRAuthAPNSToken.h"
+#import "FIRAuthGlobalWorkQueue.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @var kRegistrationTimeout
+ @brief Timeout for registration for remote notification.
+ @remarks Once we start to handle `application:didFailToRegisterForRemoteNotificationsWithError:`
+ we probably don't have to use timeout at all.
+ */
+static const NSTimeInterval kRegistrationTimeout = 5;
+
+/** @var kLegacyRegistrationTimeout
+ @brief Timeout for registration for remote notification on iOS 7.
+ */
+static const NSTimeInterval kLegacyRegistrationTimeout = 30;
+
+@implementation FIRAuthAPNSTokenManager {
+ /** @var _application
+ @brief The @c UIApplication to request the token from.
+ */
+ UIApplication *_application;
+
+ /** @var _pendingCallbacks
+ @brief The list of all pending callbacks for the APNs token.
+ */
+ NSMutableArray<FIRAuthAPNSTokenCallback> *_pendingCallbacks;
+}
+
+- (instancetype)initWithApplication:(UIApplication *)application {
+ self = [super init];
+ if (self) {
+ _application = application;
+ _timeout = [_application respondsToSelector:@selector(registerForRemoteNotifications)] ?
+ kRegistrationTimeout : kLegacyRegistrationTimeout;
+ }
+ return self;
+}
+
+- (void)getTokenWithCallback:(FIRAuthAPNSTokenCallback)callback {
+ if (_token) {
+ callback(_token);
+ return;
+ }
+ if (_pendingCallbacks) {
+ [_pendingCallbacks addObject:callback];
+ return;
+ }
+ _pendingCallbacks =
+ [[NSMutableArray<FIRAuthAPNSTokenCallback> alloc] initWithObjects:callback, nil];
+ dispatch_async(dispatch_get_main_queue(), ^{
+ if ([_application respondsToSelector:@selector(registerForRemoteNotifications)]) {
+ [_application registerForRemoteNotifications];
+ } else {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+ [_application registerForRemoteNotificationTypes:UIRemoteNotificationTypeAlert];
+#pragma clang diagnostic pop
+ }
+ });
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_timeout * NSEC_PER_SEC)),
+ FIRAuthGlobalWorkQueue(), ^{
+ [self callBack];
+ });
+}
+
+- (void)setToken:(nullable FIRAuthAPNSToken *)token {
+ if (!token) {
+ _token = nil;
+ return;
+ }
+ if (token.type == FIRAuthAPNSTokenTypeUnknown) {
+ static FIRAuthAPNSTokenType detectedTokenType = FIRAuthAPNSTokenTypeUnknown;
+ if (detectedTokenType == FIRAuthAPNSTokenTypeUnknown) {
+ detectedTokenType =
+ [[self class] isProductionApp] ? FIRAuthAPNSTokenTypeProd : FIRAuthAPNSTokenTypeSandbox;
+ }
+ token = [[FIRAuthAPNSToken alloc] initWithData:token.data type:detectedTokenType];
+ }
+ _token = token;
+ [self callBack];
+}
+
+#pragma mark - Internal methods
+
+/** @fn callBack
+ @brief Calls back all pending callbacks with the current APNs token, if one is available.
+ */
+- (void)callBack {
+ if (!_pendingCallbacks) {
+ return;
+ }
+ NSArray<FIRAuthAPNSTokenCallback> *allCallbacks = _pendingCallbacks;
+ _pendingCallbacks = nil;
+ for (FIRAuthAPNSTokenCallback callback in allCallbacks) {
+ callback(_token);
+ }
+};
+
+/** @fn isProductionApp
+ @brief Whether or not the app has production (versus sandbox) provisioning profile.
+ @remarks This method is adapted from @c FIRInstanceID .
+ */
++ (BOOL)isProductionApp {
+ const BOOL defaultAppTypeProd = YES;
+
+ NSError *error = nil;
+
+ Class envClass = NSClassFromString(@"FIRAppEnvironmentUtil");
+ SEL isSimulatorSelector = NSSelectorFromString(@"isSimulator");
+ if ([envClass respondsToSelector:isSimulatorSelector]) {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
+ if ([envClass performSelector:isSimulatorSelector]) {
+#pragma clang diagnostic pop
+ FIRLogWarning(kFIRLoggerAuth, @"I-AUT000006",
+ @"Assuming prod APNs token type on simulator.");
+ return defaultAppTypeProd;
+ }
+ }
+
+ NSString *path = [[[NSBundle mainBundle] bundlePath]
+ stringByAppendingPathComponent:@"embedded.mobileprovision"];
+
+ // Apps distributed via AppStore or TestFlight use the Production APNS certificates.
+ SEL isFromAppStoreSelector = NSSelectorFromString(@"isFromAppStore");
+ if ([envClass respondsToSelector:isFromAppStoreSelector]) {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
+ if ([envClass performSelector:isFromAppStoreSelector]) {
+#pragma clang diagnostic pop
+ return defaultAppTypeProd;
+ }
+ }
+
+ SEL isAppStoreReceiptSandboxSelector = NSSelectorFromString(@"isAppStoreReceiptSandbox");
+ if ([envClass respondsToSelector:isAppStoreReceiptSandboxSelector]) {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
+ if ([envClass performSelector:isAppStoreReceiptSandboxSelector] && !path.length) {
+#pragma clang diagnostic pop
+ // Distributed via TestFlight
+ return defaultAppTypeProd;
+ }
+ }
+
+ NSMutableData *profileData = [NSMutableData dataWithContentsOfFile:path options:0 error:&error];
+
+ if (!profileData.length || error) {
+ FIRLogWarning(kFIRLoggerAuth, @"I-AUT000007",
+ @"Error while reading embedded mobileprovision %@", error);
+ return defaultAppTypeProd;
+ }
+
+ // The "embedded.mobileprovision" sometimes contains characters with value 0, which signals the
+ // end of a c-string and halts the ASCII parser, or with value > 127, which violates strict 7-bit
+ // ASCII. Replace any 0s or invalid characters in the input.
+ uint8_t *profileBytes = (uint8_t *)profileData.bytes;
+ for (int i = 0; i < profileData.length; i++) {
+ uint8_t currentByte = profileBytes[i];
+ if (!currentByte || currentByte > 127) {
+ profileBytes[i] = '.';
+ }
+ }
+
+ NSString *embeddedProfile = [[NSString alloc] initWithBytesNoCopy:profileBytes
+ length:profileData.length
+ encoding:NSASCIIStringEncoding
+ freeWhenDone:NO];
+
+ if (error || !embeddedProfile.length) {
+ FIRLogWarning(kFIRLoggerAuth, @"I-AUT000008",
+ @"Error while reading embedded mobileprovision %@", error);
+ return defaultAppTypeProd;
+ }
+
+ NSScanner *scanner = [NSScanner scannerWithString:embeddedProfile];
+ NSString *plistContents;
+ if ([scanner scanUpToString:@"<plist" intoString:nil]) {
+ if ([scanner scanUpToString:@"</plist>" intoString:&plistContents]) {
+ plistContents = [plistContents stringByAppendingString:@"</plist>"];
+ }
+ }
+
+ if (!plistContents.length) {
+ return defaultAppTypeProd;
+ }
+
+ NSData *data = [plistContents dataUsingEncoding:NSUTF8StringEncoding];
+ if (!data.length) {
+ FIRLogWarning(kFIRLoggerAuth, @"I-AUT000009",
+ @"Couldn't read plist fetched from embedded mobileprovision");
+ return defaultAppTypeProd;
+ }
+
+ NSError *plistMapError;
+ id plistData = [NSPropertyListSerialization propertyListWithData:data
+ options:NSPropertyListImmutable
+ format:nil
+ error:&plistMapError];
+ if (plistMapError || ![plistData isKindOfClass:[NSDictionary class]]) {
+ FIRLogWarning(kFIRLoggerAuth, @"I-AUT000010",
+ @"Error while converting assumed plist to dict %@",
+ plistMapError.localizedDescription);
+ return defaultAppTypeProd;
+ }
+ NSDictionary *plistMap = (NSDictionary *)plistData;
+
+ if ([plistMap valueForKeyPath:@"ProvisionedDevices"]) {
+ FIRLogInfo(kFIRLoggerAuth, @"I-AUT000011",
+ @"Provisioning profile has specifically provisioned devices, "
+ @"most likely a Dev profile.");
+ }
+
+ NSString *apsEnvironment = [plistMap valueForKeyPath:@"Entitlements.aps-environment"];
+ FIRLogDebug(kFIRLoggerAuth, @"I-AUT000012",
+ @"APNS Environment in profile: %@", apsEnvironment);
+
+ // No aps-environment in the profile.
+ if (!apsEnvironment.length) {
+ FIRLogWarning(kFIRLoggerAuth, @"I-AUT000013",
+ @"No aps-environment set. If testing on a device APNS is not "
+ @"correctly configured. Please recheck your provisioning profiles.");
+ return defaultAppTypeProd;
+ }
+
+ if ([apsEnvironment isEqualToString:@"development"]) {
+ return NO;
+ }
+
+ return defaultAppTypeProd;
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/FIRAuthAPNSTokenType.h b/Firebase/Auth/Source/FIRAuthAPNSTokenType.h
new file mode 100644
index 0000000..87df574
--- /dev/null
+++ b/Firebase/Auth/Source/FIRAuthAPNSTokenType.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "FIRAuthSwiftNameSupport.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ * @brief The APNs token type for the app.
+ */
+typedef NS_ENUM(NSInteger, FIRAuthAPNSTokenType) {
+
+ /** Unknown token type.
+ The actual token type will be detected from the provisioning profile in the app's bundle.
+ */
+ FIRAuthAPNSTokenTypeUnknown,
+
+ /** Sandbox token type.
+ */
+ FIRAuthAPNSTokenTypeSandbox,
+
+ /** Production token type.
+ */
+ FIRAuthAPNSTokenTypeProd,
+} FIR_SWIFT_NAME(AuthAPNSTokenType);
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/FIRAuthAppCredential.m b/Firebase/Auth/Source/FIRAuthAppCredential.m
new file mode 100644
index 0000000..ad12741
--- /dev/null
+++ b/Firebase/Auth/Source/FIRAuthAppCredential.m
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "Private/FIRAuthAppCredential.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @var kReceiptKey
+ @brief The key used to encode the receipt property for NSSecureCoding.
+ */
+static NSString *const kReceiptKey = @"receipt";
+
+/** @var kSecretKey
+ @brief The key used to encode the secret property for NSSecureCoding.
+ */
+static NSString *const kSecretKey = @"secret";
+
+@implementation FIRAuthAppCredential
+
+- (instancetype)initWithReceipt:(NSString *)receipt secret:(nullable NSString *)secret {
+ self = [super init];
+ if (self) {
+ _receipt = [receipt copy];
+ _secret = [secret copy];
+ }
+ return self;
+}
+
+#pragma mark - NSSecureCoding
+
++ (BOOL)supportsSecureCoding {
+ return YES;
+}
+
+- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder {
+ NSString *receipt = [aDecoder decodeObjectOfClass:[NSString class] forKey:kReceiptKey];
+ if (!receipt) {
+ return nil;
+ }
+ NSString *secret = [aDecoder decodeObjectOfClass:[NSString class] forKey:kSecretKey];
+ return [self initWithReceipt:receipt secret:secret];
+}
+
+- (void)encodeWithCoder:(NSCoder *)aCoder {
+ [aCoder encodeObject:_receipt forKey:kReceiptKey];
+ [aCoder encodeObject:_secret forKey:kSecretKey];
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/FIRAuthAppCredentialManager.m b/Firebase/Auth/Source/FIRAuthAppCredentialManager.m
new file mode 100644
index 0000000..2a0d1c7
--- /dev/null
+++ b/Firebase/Auth/Source/FIRAuthAppCredentialManager.m
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "Private/FIRAuthAppCredentialManager.h"
+
+#import "Private/FIRAuthAppCredential.h"
+#import "FIRAuthGlobalWorkQueue.h"
+#import "FIRAuthKeychain.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @var kKeychainDataKey
+ @brief The keychain key for the data.
+ */
+static NSString *const kKeychainDataKey = @"app_credentials";
+
+/** @var kFullCredentialKey
+ @brief The data key for the full app credential.
+ */
+static NSString *const kFullCredentialKey = @"full_credential";
+
+/** @var kPendingReceiptsKey
+ @brief The data key for the array of pending receipts.
+ */
+static NSString *const kPendingReceiptsKey = @"pending_receipts";
+
+/** @var kMaximumNumberOfPendingReceipts
+ @brief The maximum number of partial credentials kept by this class.
+ */
+static const NSUInteger kMaximumNumberOfPendingReceipts = 32;
+
+@implementation FIRAuthAppCredentialManager {
+ /** @var _keychain
+ @brief The keychain for app credentials to load from and to save to.
+ */
+ FIRAuthKeychain *_keychain;
+
+ /** @var _pendingReceipts
+ @brief A list of pending receipts sorted in the order they were recorded.
+ */
+ NSMutableArray<NSString *> *_pendingReceipts;
+
+ /** @var _callbacksByReceipt
+ @brief A map from pending receipts to callbacks.
+ */
+ NSMutableDictionary<NSString *, FIRAuthAppCredentialCallback> *_callbacksByReceipt;
+}
+
+- (instancetype)initWithKeychain:(FIRAuthKeychain *)keychain {
+ self = [super init];
+ if (self) {
+ _keychain = keychain;
+ // Load the credentials from keychain if possible.
+ NSError *error;
+ NSData *encodedData = [_keychain dataForKey:kKeychainDataKey error:&error];
+ if (!error && encodedData) {
+ NSKeyedUnarchiver *unarchiver =
+ [[NSKeyedUnarchiver alloc] initForReadingWithData:encodedData];
+ FIRAuthAppCredential *credential =
+ [unarchiver decodeObjectOfClass:[FIRAuthAppCredential class]
+ forKey:kFullCredentialKey];
+ if ([credential isKindOfClass:[FIRAuthAppCredential class]]) {
+ _credential = credential;
+ }
+ NSSet<Class> *allowedClasses =
+ [NSSet<Class> setWithObjects:[NSArray class], [NSString class], nil];
+ NSArray<NSString *> *pendingReceipts =
+ [unarchiver decodeObjectOfClasses:allowedClasses forKey:kPendingReceiptsKey];
+ if ([pendingReceipts isKindOfClass:[NSArray class]]) {
+ _pendingReceipts = [pendingReceipts mutableCopy];
+ }
+ }
+ if (!_pendingReceipts) {
+ _pendingReceipts = [[NSMutableArray<NSString *> alloc] init];
+ }
+ _callbacksByReceipt =
+ [[NSMutableDictionary<NSString *, FIRAuthAppCredentialCallback> alloc] init];
+ }
+ return self;
+}
+
+- (NSUInteger)maximumNumberOfPendingReceipts {
+ return kMaximumNumberOfPendingReceipts;
+}
+
+- (void)didStartVerificationWithReceipt:(NSString *)receipt
+ timeout:(NSTimeInterval)timeout
+ callback:(FIRAuthAppCredentialCallback)callback {
+ [_pendingReceipts removeObject:receipt];
+ if (_pendingReceipts.count >= kMaximumNumberOfPendingReceipts) {
+ [_pendingReceipts removeObjectAtIndex:0];
+ }
+ [_pendingReceipts addObject:receipt];
+ _callbacksByReceipt[receipt] = callback;
+ [self saveData];
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeout * NSEC_PER_SEC)),
+ FIRAuthGlobalWorkQueue(), ^{
+ [self callBackWithReceipt:receipt];
+ });
+}
+
+- (BOOL)canFinishVerificationWithReceipt:(NSString *)receipt secret:(NSString *)secret {
+ if (![_pendingReceipts containsObject:receipt]) {
+ return NO;
+ }
+ [_pendingReceipts removeObject:receipt];
+ _credential = [[FIRAuthAppCredential alloc] initWithReceipt:receipt secret:secret];
+ [self saveData];
+ [self callBackWithReceipt:receipt];
+ return YES;
+}
+
+- (void)clearCredential {
+ _credential = nil;
+ [self saveData];
+}
+
+#pragma mark - Internal methods
+
+/** @fn saveData
+ @brief Save the data in memory to the keychain ignoring any errors.
+ */
+- (void)saveData {
+ NSMutableData *archiveData = [NSMutableData data];
+ NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:archiveData];
+ [archiver encodeObject:_credential forKey:kFullCredentialKey];
+ [archiver encodeObject:_pendingReceipts forKey:kPendingReceiptsKey];
+ [archiver finishEncoding];
+ [_keychain setData:archiveData forKey:kKeychainDataKey error:NULL];
+}
+
+/** @fn callBackWithReceipt:
+ @brief Calls the saved callback for the specifc receipt.
+ @param receipt The receipt associated with the callback.
+ */
+- (void)callBackWithReceipt:(NSString *)receipt {
+ FIRAuthAppCredentialCallback callback = _callbacksByReceipt[receipt];
+ if (!callback) {
+ return;
+ }
+ [_callbacksByReceipt removeObjectForKey:receipt];
+ if (_credential) {
+ callback(_credential);
+ } else {
+ callback([[FIRAuthAppCredential alloc] initWithReceipt:receipt secret:nil]);
+ }
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/FIRAuthAppDelegateProxy.m b/Firebase/Auth/Source/FIRAuthAppDelegateProxy.m
new file mode 100644
index 0000000..ca88a4c
--- /dev/null
+++ b/Firebase/Auth/Source/FIRAuthAppDelegateProxy.m
@@ -0,0 +1,245 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "Private/FIRAuthAppDelegateProxy.h"
+
+#import <objc/runtime.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @var kProxyEnabledBundleKey
+ @brief The key in application's bundle plist for whether or not proxy should be enabled.
+ @remarks This key is a shared constant with Analytics and FCM.
+ */
+static NSString *const kProxyEnabledBundleKey = @"FirebaseAppDelegateProxyEnabled";
+
+/** @fn noop
+ @brief A function that does nothing.
+ @remarks This is used as the placeholder for unimplemented UApplicationDelegate methods,
+ because once we added a method there is no way to remove it from the class.
+ */
+#if !OBJC_OLD_DISPATCH_PROTOTYPES
+static void noop(void) {
+}
+#else
+static id noop(id object, SEL cmd, ...) {
+ return nil;
+}
+#endif
+
+@implementation FIRAuthAppDelegateProxy {
+ /** @var _appDelegate
+ @brief The application delegate whose method is being swizzled.
+ */
+ id<UIApplicationDelegate> _appDelegate;
+
+ /** @var _orginalImplementationsBySelector
+ @brief A map from selectors to original implementations that have been swizzled.
+ */
+ NSMutableDictionary<NSValue *, NSValue *> *_originalImplementationsBySelector;
+
+ /** @var _handlers
+ @brief The array of weak pointers of `id<FIRAuthAppDelegateHandler>`.
+ */
+ NSPointerArray *_handlers;
+}
+
+- (nullable instancetype)initWithApplication:(nullable UIApplication *)application {
+ self = [super init];
+ if (self) {
+ id proxyEnabled = [[NSBundle mainBundle] objectForInfoDictionaryKey:kProxyEnabledBundleKey];
+ if ([proxyEnabled isKindOfClass:[NSNumber class]] && !((NSNumber *)proxyEnabled).boolValue) {
+ return nil;
+ }
+ _appDelegate = application.delegate;
+ if (![_appDelegate conformsToProtocol:@protocol(UIApplicationDelegate)]) {
+ return nil;
+ }
+ _originalImplementationsBySelector = [[NSMutableDictionary<NSValue *, NSValue *> alloc] init];
+ _handlers = [[NSPointerArray alloc] initWithOptions:NSPointerFunctionsWeakMemory];
+
+ // Swizzle the methods.
+ __weak FIRAuthAppDelegateProxy *weakSelf = self;
+ SEL registerDeviceTokenSelector =
+ @selector(application:didRegisterForRemoteNotificationsWithDeviceToken:);
+ [self replaceSelector:registerDeviceTokenSelector
+ withBlock:^(id object, UIApplication* application, NSData *deviceToken) {
+ [weakSelf object:object
+ selector:registerDeviceTokenSelector
+ application:application
+ didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
+ }];
+ SEL receiveNotificationSelector = @selector(application:didReceiveRemoteNotification:);
+ SEL receiveNotificationWithHandlerSelector =
+ @selector(application:didReceiveRemoteNotification:fetchCompletionHandler:);
+ if ([_appDelegate respondsToSelector:receiveNotificationWithHandlerSelector] ||
+ ![_appDelegate respondsToSelector:receiveNotificationSelector]) {
+ // Replace the modern selector which is available on iOS 7 and above.
+ [self replaceSelector:receiveNotificationWithHandlerSelector
+ withBlock:^(id object, UIApplication *application, NSDictionary *notification,
+ void (^completionHandler)(UIBackgroundFetchResult)) {
+ [weakSelf object:object
+ selector:receiveNotificationWithHandlerSelector
+ application:application
+ didReceiveRemoteNotification:notification
+ fetchCompletionHandler:completionHandler];
+ }];
+ } else {
+ // Replace the deprecated selector because this is the only one that the client app uses.
+ [self replaceSelector:receiveNotificationSelector
+ withBlock:^(id object, UIApplication *application, NSDictionary *notification) {
+ [weakSelf object:object
+ selector:receiveNotificationSelector
+ application:application
+ didReceiveRemoteNotification:notification];
+ }];
+ }
+ }
+ return self;
+}
+
+- (void)dealloc {
+ for (NSValue *selector in _originalImplementationsBySelector) {
+ IMP implementation = _originalImplementationsBySelector[selector].pointerValue;
+ Method method = class_getInstanceMethod([_appDelegate class], selector.pointerValue);
+ imp_removeBlock(method_setImplementation(method, implementation));
+ }
+}
+
+- (void)addHandler:(__weak id<FIRAuthAppDelegateHandler>)handler {
+ @synchronized (_handlers) {
+ [_handlers addPointer:(__bridge void *)handler];
+ }
+}
+
++ (nullable instancetype)sharedInstance {
+ static dispatch_once_t onceToken;
+ static FIRAuthAppDelegateProxy *_Nullable sharedInstance;
+ dispatch_once(&onceToken, ^{
+ sharedInstance = [[self alloc] initWithApplication:[UIApplication sharedApplication]];
+ });
+ return sharedInstance;
+}
+
+#pragma mark - UIApplicationDelegate proxy methods.
+
+- (void)object:(id)object
+ selector:(SEL)selector
+ application:(UIApplication *)application
+ didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
+ if (object == _appDelegate) {
+ for (id<FIRAuthAppDelegateHandler> handler in [self handlers]) {
+ [handler setAPNSToken:deviceToken];
+ }
+ }
+ IMP originalImplementation = [self originalImplementationForSelector:selector];
+ if (originalImplementation) {
+ typedef void (*Implmentation)(id, SEL, UIApplication*, NSData *);
+ ((Implmentation)originalImplementation)(object, selector, application, deviceToken);
+ }
+}
+
+- (void)object:(id)object
+ selector:(SEL)selector
+ application:(UIApplication *)application
+ didReceiveRemoteNotification:(NSDictionary *)notification
+ fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
+ if (object == _appDelegate) {
+ for (id<FIRAuthAppDelegateHandler> handler in [self handlers]) {
+ if ([handler canHandleNotification:notification]) {
+ completionHandler(UIBackgroundFetchResultNoData);
+ return;
+ };
+ }
+ }
+ IMP originalImplementation = [self originalImplementationForSelector:selector];
+ typedef void (*Implmentation)(id, SEL, UIApplication*, NSDictionary *,
+ void (^)(UIBackgroundFetchResult));
+ ((Implmentation)originalImplementation)(object, selector, application, notification,
+ completionHandler);
+}
+
+- (void)object:(id)object
+ selector:(SEL)selector
+ application:(UIApplication *)application
+ didReceiveRemoteNotification:(NSDictionary *)notification {
+ if (object == _appDelegate) {
+ for (id<FIRAuthAppDelegateHandler> handler in [self handlers]) {
+ if ([handler canHandleNotification:notification]) {
+ return;
+ };
+ }
+ }
+ IMP originalImplementation = [self originalImplementationForSelector:selector];
+ typedef void (*Implmentation)(id, SEL, UIApplication*, NSDictionary *);
+ ((Implmentation)originalImplementation)(object, selector, application, notification);
+}
+
+#pragma mark - Internal Methods
+
+/** @fn handlers
+ @brief Gets the list of handlers from `_handlers` safely.
+ */
+- (NSArray<id<FIRAuthAppDelegateHandler>> *)handlers {
+ @synchronized (_handlers) {
+ NSMutableArray<id<FIRAuthAppDelegateHandler>> *liveHandlers =
+ [[NSMutableArray<id<FIRAuthAppDelegateHandler>> alloc] initWithCapacity:_handlers.count];
+ for (__weak id<FIRAuthAppDelegateHandler> handler in _handlers) {
+ if (handler) {
+ [liveHandlers addObject:handler];
+ }
+ }
+ if (liveHandlers.count < _handlers.count) {
+ [_handlers compact];
+ }
+ return liveHandlers;
+ }
+}
+
+/** @fn replaceSelector:withBlock:
+ @brief replaces the implementation for a method of `_appDelegate` specified by a selector.
+ @param selector The selector for the method.
+ @param block The block as the new implementation of the method.
+ */
+- (void)replaceSelector:(SEL)selector withBlock:(id)block {
+ Method originalMethod = class_getInstanceMethod([_appDelegate class], selector);
+ IMP newImplementation = imp_implementationWithBlock(block);
+ IMP originalImplementation;
+ if (originalMethod) {
+ originalImplementation = method_setImplementation(originalMethod, newImplementation) ?: &noop;
+ } else {
+ // The original method was not implemented in the class, add it with the new implementation.
+ struct objc_method_description methodDescription =
+ protocol_getMethodDescription(@protocol(UIApplicationDelegate), selector, NO, YES);
+ class_addMethod([_appDelegate class], selector, newImplementation, methodDescription.types);
+ originalImplementation = &noop;
+ }
+ _originalImplementationsBySelector[[NSValue valueWithPointer:selector]] =
+ [NSValue valueWithPointer:originalImplementation];
+}
+
+/** @fn originalImplementationForSelector:
+ @brief Gets the original implementation for the given selector.
+ @param selector The selector for the method that has been replaced.
+ @return The original implementation if there was one.
+ */
+- (IMP)originalImplementationForSelector:(SEL)selector {
+ return _originalImplementationsBySelector[[NSValue valueWithPointer:selector]].pointerValue;
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/FIRAuthCredential.h b/Firebase/Auth/Source/FIRAuthCredential.h
new file mode 100644
index 0000000..ce28854
--- /dev/null
+++ b/Firebase/Auth/Source/FIRAuthCredential.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "FIRAuthSwiftNameSupport.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @class FIRAuthCredential
+ @brief Represents a credential.
+ */
+FIR_SWIFT_NAME(AuthCredential)
+@interface FIRAuthCredential : NSObject
+
+/** @property provider
+ @brief Gets the name of the identity provider for the credential.
+ */
+@property(nonatomic, copy, readonly) NSString *provider;
+
+/** @fn init
+ @brief This is an abstract base class. Concrete instances should be created via factory
+ methods available in the various authentication provider libraries (like the Facebook
+ provider or the Google provider libraries.)
+ */
+- (instancetype)init NS_UNAVAILABLE;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/FIRAuthCredential.m b/Firebase/Auth/Source/FIRAuthCredential.m
new file mode 100644
index 0000000..d476d6d
--- /dev/null
+++ b/Firebase/Auth/Source/FIRAuthCredential.m
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "Private/FIRAuthCredential_Internal.h"
+
+@implementation FIRAuthCredential
+
+- (instancetype)init {
+ @throw [NSException exceptionWithName:@"Attempt to call unavailable initializer."
+ reason:@"This class is an abstract base class. It's init method "
+ "should not be called directly."
+ userInfo:nil];
+}
+
+- (nullable instancetype)initWithProvider:(NSString *)provider {
+ self = [super init];
+ if (self) {
+ _provider = [provider copy];
+ }
+ return self;
+}
+
+- (void)prepareVerifyAssertionRequest:(FIRVerifyAssertionRequest *)request {
+ @throw [NSException exceptionWithName:@"Attempt to call virtual method."
+ reason:@"This method must be overridden by a subclass."
+ userInfo:nil];
+}
+
+@end
diff --git a/Firebase/Auth/Source/FIRAuthDataResult.h b/Firebase/Auth/Source/FIRAuthDataResult.h
new file mode 100644
index 0000000..e72adf2
--- /dev/null
+++ b/Firebase/Auth/Source/FIRAuthDataResult.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "FIRAuthSwiftNameSupport.h"
+
+@class FIRAdditionalUserInfo;
+@class FIRUser;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @class FIRAuthDataResult
+ @brief Helper object that contains the result of a successful sign-in, link and reauthenticate.
+ It contains a reference to a @c FIRUser and @c FIRAdditionalUserInfo.
+ */
+FIR_SWIFT_NAME(AuthDataResult)
+@interface FIRAuthDataResult : NSObject
+
+/** @fn init
+ @brief This class should not be initialized manually. @c FIRAuthDataResult instance is
+ returned as part of @c FIRAuthDataResultCallback .
+ */
+- (instancetype)init NS_UNAVAILABLE;
+
+/** @property user
+ @brief The signed in user.
+ */
+@property(nonatomic, readonly) FIRUser *user;
+
+/** @property additionalUserInfo
+ @brief If available contains the additional IdP specific information about signed in user.
+ */
+@property(nonatomic, readonly, nullable) FIRAdditionalUserInfo *additionalUserInfo;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/FIRAuthDataResult.m b/Firebase/Auth/Source/FIRAuthDataResult.m
new file mode 100644
index 0000000..fd2daa7
--- /dev/null
+++ b/Firebase/Auth/Source/FIRAuthDataResult.m
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "Private/FIRAuthDataResult_Internal.h"
+
+#import "FIRAdditionalUserInfo.h"
+#import "FIRUser.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@implementation FIRAuthDataResult
+
+/** @var kAdditionalUserInfoCodingKey
+ @brief The key used to encode the additionalUserInfo property for NSSecureCoding.
+ */
+static NSString *const kAdditionalUserInfoCodingKey = @"additionalUserInfo";
+
+/** @var kUserCodingKey
+ @brief The key used to encode the user property for NSSecureCoding.
+ */
+static NSString *const kUserCodingKey = @"user";
+
+- (nullable instancetype)initWithUser:(FIRUser *)user
+ additionalUserInfo:(nullable FIRAdditionalUserInfo *)additionalUserInfo {
+ self = [super init];
+ if (self) {
+ _additionalUserInfo = additionalUserInfo;
+ _user = user;
+ }
+ return self;
+}
+
+#pragma mark - NSSecureCoding
+
++ (BOOL)supportsSecureCoding {
+ return YES;
+}
+
+- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder {
+ FIRUser *user =
+ [aDecoder decodeObjectOfClass:[FIRUser class] forKey:kUserCodingKey];
+ FIRAdditionalUserInfo *additionalUserInfo =
+ [aDecoder decodeObjectOfClass:[FIRAdditionalUserInfo class]
+ forKey:kAdditionalUserInfoCodingKey];
+
+ return [self initWithUser:user additionalUserInfo:additionalUserInfo];
+}
+
+- (void)encodeWithCoder:(NSCoder *)aCoder {
+ [aCoder encodeObject:_user forKey:kUserCodingKey];
+ [aCoder encodeObject:_additionalUserInfo forKey:kAdditionalUserInfoCodingKey];
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/FIRAuthDispatcher.m b/Firebase/Auth/Source/FIRAuthDispatcher.m
new file mode 100644
index 0000000..98eb50a
--- /dev/null
+++ b/Firebase/Auth/Source/FIRAuthDispatcher.m
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "Private/FIRAuthDispatcher.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@implementation FIRAuthDispatcher
+
+@synthesize dispatchAfterImplementation = _dispatchAfterImplementation;
+
++ (instancetype)sharedInstance {
+ static dispatch_once_t onceToken;
+ static FIRAuthDispatcher *sharedInstance;
+ dispatch_once(&onceToken, ^{
+ sharedInstance = [[self alloc] init];
+ });
+ return sharedInstance;
+}
+
+- (void)dispatchAfterDelay:(NSTimeInterval)delay
+ queue:(dispatch_queue_t)queue
+ task:(void (^)(void))task {
+ if (_dispatchAfterImplementation) {
+ _dispatchAfterImplementation(delay, queue, task);
+ return;
+ }
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, delay * NSEC_PER_SEC), queue, task);
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/FIRAuthErrorUtils.m b/Firebase/Auth/Source/FIRAuthErrorUtils.m
new file mode 100644
index 0000000..8179d02
--- /dev/null
+++ b/Firebase/Auth/Source/FIRAuthErrorUtils.m
@@ -0,0 +1,794 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "Private/FIRAuthErrorUtils.h"
+
+#import "FIRAuthCredential.h"
+#import "Private/FIRAuthInternalErrors.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+NSString *const FIRAuthErrorDomain = @"FIRAuthErrorDomain";
+
+NSString *const FIRAuthInternalErrorDomain = @"FIRAuthInternalErrorDomain";
+
+NSString *const FIRAuthErrorUserInfoDeserializedResponseKey =
+ @"FIRAuthErrorUserInfoDeserializedResponseKey";
+
+NSString *const FIRAuthErrorUserInfoDataKey = @"FIRAuthErrorUserInfoDataKey";
+
+NSString *const FIRAuthErrorUserInfoEmailKey = @"FIRAuthErrorUserInfoEmailKey";
+
+NSString *const FIRAuthErrorNameKey = @"error_name";
+
+NSString *const FIRAuthUpdatedCredentialKey = @"FIRAuthUpdatedCredentialKey";
+
+/** @var kServerErrorDetailMarker
+ @brief This marker indicates that the server error message contains a detail error message which
+ should be used instead of the hardcoded client error message.
+ */
+static NSString *const kServerErrorDetailMarker = @" : ";
+
+#pragma mark - Standard Error Messages
+
+/** @var kFIRAuthErrorMessageInvalidCustomToken
+ @brief Message for @c FIRAuthErrorCodeInvalidCustomToken error code.
+ */
+static NSString *const kFIRAuthErrorMessageInvalidCustomToken = @"The custom token format is "
+ "incorrect. Please check the documentation.";
+
+/** @var kFIRAuthErrorMessageCustomTokenMismatch
+ @brief Message for @c FIRAuthErrorCodeCustomTokenMismatch error code.
+ */
+static NSString *const kFIRAuthErrorMessageCustomTokenMismatch = @"The custom token corresponds to "
+ "a different audience.";
+
+/** @var kFIRAuthErrorMessageInvalidEmail
+ @brief Message for @c FIRAuthErrorCodeInvalidEmail error code.
+ */
+static NSString *const kFIRAuthErrorMessageInvalidEmail = @"The email address is badly formatted.";
+
+/** @var kFIRAuthErrorMessageInvalidCredential
+ @brief Message for @c FIRAuthErrorCodeInvalidCredential error code.
+ */
+static NSString *const kFIRAuthErrorMessageInvalidCredential = @"The supplied auth credential is "
+ "malformed or has expired.";
+
+/** @var kFIRAuthErrorMessageUserDisabled
+ @brief Message for @c FIRAuthErrorCodeUserDisabled error code.
+ */
+static NSString *const kFIRAuthErrorMessageUserDisabled = @"The user account has been disabled by "
+ "an administrator.";
+
+/** @var kFIRAuthErrorMessageEmailAlreadyInUse
+ @brief Message for @c FIRAuthErrorCodeEmailAlreadyInUse error code.
+ */
+static NSString *const kFIRAuthErrorMessageEmailAlreadyInUse = @"The email address is already in "
+ "use by another account.";
+
+/** @var kFIRAuthErrorMessageWrongPassword
+ @brief Message for @c FIRAuthErrorCodeWrongPassword error code.
+ */
+static NSString *const kFIRAuthErrorMessageWrongPassword = @"The password is invalid or the user "
+ "does not have a password.";
+
+/** @var kFIRAuthErrorMessageTooManyRequests
+ @brief Message for @c FIRAuthErrorCodeTooManyRequests error code.
+ */
+static NSString *const kFIRAuthErrorMessageTooManyRequests = @"We have blocked all requests from "
+ "this device due to unusual activity. Try again later.";
+
+/** @var kFIRAuthErrorMessageAccountExistsWithDifferentCredential
+ @brief Message for @c FIRAuthErrorCodeAccountLinkNeeded error code.
+ */
+static NSString *const kFIRAuthErrorMessageAccountExistsWithDifferentCredential = @"An account "
+ "already exists with the same email address but different sign-in credentials. Sign in using a "
+ "provider associated with this email address.";
+
+/** @var kFIRAuthErrorMessageRequiresRecentLogin
+ @brief Message for @c FIRAuthErrorCodeRequiresRecentLogin error code.
+ */
+static NSString *const kFIRAuthErrorMessageRequiresRecentLogin= @"This operation is sensitive and "
+ "requires recent authentication. Log in again before retrying this request.";
+
+/** @var kFIRAuthErrorMessageProviderAlreadyLinked
+ @brief Message for @c FIRAuthErrorCodeProviderAlreadyExists error code.
+ */
+static NSString *const kFIRAuthErrorMessageProviderAlreadyLinked =
+ @"[ERROR_PROVIDER_ALREADY_LINKED] - User can only be linked to one identity for the given "
+ "provider.";
+
+/** @var kFIRAuthErrorMessageNoSuchProvider
+ @brief Message for @c FIRAuthErrorCodeNoSuchProvider error code.
+ */
+static NSString *const kFIRAuthErrorMessageNoSuchProvider = @"User was not linked to an account "
+ "with the given provider.";
+
+/** @var kFIRAuthErrorMessageInvalidUserToken
+ @brief Message for @c FIRAuthErrorCodeInvalidUserToken error code.
+ */
+static NSString *const kFIRAuthErrorMessageInvalidUserToken = @"The user's credential is no longer "
+ "valid. The user must sign in again.";
+
+/** @var kFIRAuthErrorMessageNetworkError
+ @brief Message for @c FIRAuthErrorCodeNetworkError error code.
+ */
+static NSString *const kFIRAuthErrorMessageNetworkError = @"Network error (such as timeout, "
+ "interrupted connection or unreachable host) has occurred.";
+
+/** @var kFIRAuthErrorMessageKeychainError
+ @brief Message for @c FIRAuthErrorCodeKeychainError error code.
+ */
+static NSString *const kFIRAuthErrorMessageKeychainError = @"An error occurred when accessing the "
+ "keychain. The @c NSLocalizedFailureReasonErrorKey field in the @c NSError.userInfo dictionary "
+ "will contain more information about the error encountered";
+
+/** @var kFIRAuthErrorMessageUserTokenExpired
+ @brief Message for @c FIRAuthErrorCodeTokenExpired error code.
+ */
+static NSString *const kFIRAuthErrorMessageUserTokenExpired = @"The user's credential is no longer "
+ "valid. The user must sign in again.";
+
+/** @var kFIRAuthErrorMessageUserNotFound
+ @brief Message for @c FIRAuthErrorCodeUserNotFound error code.
+ */
+static NSString *const kFIRAuthErrorMessageUserNotFound = @"There is no user record corresponding "
+ "to this identifier. The user may have been deleted.";
+
+/** @var kFIRAuthErrorMessageInvalidAPIKey
+ @brief Message for @c FIRAuthErrorCodeInvalidAPIKey error code.
+ @remarks This error is not thrown by the server.
+ */
+static NSString *const kFIRAuthErrorMessageInvalidAPIKey = @"An invalid API Key was supplied in "
+ "the request.";
+
+/** @var kFIRAuthErrorMessageUserMismatch.
+ @brief Message for @c FIRAuthErrorCodeInvalidAPIKey error code.
+ */
+static NSString *const FIRAuthErrorMessageUserMismatch = @"The supplied credentials do not "
+ "correspond to the previously signed in user.";
+
+/** @var kFIRAuthErrorMessageCredentialAlreadyInUse
+ @brief Message for @c FIRAuthErrorCodeCredentialAlreadyInUse error code.
+ */
+static NSString *const kFIRAuthErrorMessageCredentialAlreadyInUse = @"This credential is already "
+ "associated with a different user account.";
+
+/** @var kFIRAuthErrorMessageOperationNotAllowed
+ @brief Message for @c FIRAuthErrorCodeOperationNotAllowed error code.
+ */
+static NSString *const kFIRAuthErrorMessageOperationNotAllowed = @"The given sign-in provider is "
+ "disabled for this Firebase project. Enable it in the Firebase console, under the sign-in "
+ "method tab of the Auth section.";
+
+/** @var kFIRAuthErrorMessageWeakPassword
+ @brief Message for @c FIRAuthErrorCodeWeakPassword error code.
+ */
+static NSString *const kFIRAuthErrorMessageWeakPassword = @"The password must be 6 characters long "
+ "or more.";
+
+/** @var kFIRAuthErrorMessageAppNotAuthorized
+ @brief Message for @c FIRAuthErrorCodeAppNotAuthorized error code.
+ */
+static NSString *const kFIRAuthErrorMessageAppNotAuthorized = @"This app is not authorized to use "
+ "Firebase Authentication with the provided API key. Review your key configuration in the "
+ "Google API console and ensure that it accepts requests from your app's bundle ID.";
+
+/** @var kFIRAuthErrorMessageExpiredActionCode
+ @brief Message for @c FIRAuthErrorCodeExpiredActionCode error code.
+ */
+static NSString *const kFIRAuthErrorMessageExpiredActionCode = @"The action code has expired.";
+
+/** @var kFIRAuthErrorMessageInvalidActionCode
+ @brief Message for @c FIRAuthErrorCodeInvalidActionCode error code.
+ */
+static NSString *const kFIRAuthErrorMessageInvalidActionCode = @"The action code is invalid. This "
+ "can happen if the code is malformed, expired, or has already been used.";
+
+/** @var kFIRAuthErrorMessageInvalidMessagePayload
+ @brief Message for @c FIRAuthErrorCodeInvalidMessagePayload error code.
+ */
+static NSString *const kFIRAuthErrorMessageInvalidMessagePayload = @"The action code is invalid. "
+ "This can happen if the code is malformed, expired, or has already been used.";
+
+/** @var kFIRAuthErrorMessageInvalidSender
+ @brief Message for @c FIRAuthErrorCodeInvalidSender error code.
+ */
+static NSString *const kFIRAuthErrorMessageInvalidSender = @"The email template corresponding to "
+ "this action contains invalid characters in its message. Please fix by going to the Auth email "
+ "templates section in the Firebase Console.";
+
+/** @var kFIRAuthErrorMessageInvalidRecipientEmail
+ @brief Message for @c FIRAuthErrorCodeInvalidRecipient error code.
+ */
+static NSString *const kFIRAuthErrorMessageInvalidRecipientEmail = @"The action code is invalid. "
+ "This can happen if the code is malformed, expired, or has already been used.";
+
+/** @var kFIRAuthErrorMessageMissingContinueURI
+ @brief Message for @c FIRAuthErrorCodeMissingContinueURI error code.
+ */
+static NSString *const kFIRAuthErrorMessageMissingContinueURI =
+ @"A continue URL must be provided in the request.";
+
+/** @var kFIRAuthErrorMessageMissingPhoneNumber
+ @brief Message for @c FIRAuthErrorCodeMissingPhoneNumber error code.
+ */
+static NSString *const kFIRAuthErrorMessageMissingPhoneNumber =
+ @"To send verification codes, provide a phone number for the recipient.";
+
+/** @var kFIRAuthErrorMessageInvalidPhoneNumber
+ @brief Message for @c FIRAuthErrorCodeMissingPhoneNumber error code.
+ */
+static NSString *const kFIRAuthErrorMessageInvalidPhoneNumber =
+ @"The format of the phone number provided is incorrect. Please enter the phone number in a "
+ "format that can be parsed into E.164 format. E.164 phone numbers are written in the format "
+ "[+][country code][subscriber number including area code].";
+
+/** @var kFIRAuthErrorMessageMissingVerificationCode
+ @brief Message for @c FIRAuthErrorCodeMissingVerificationCode error code.
+ */
+static NSString *const kFIRAuthErrorMessageMissingVerificationCode =
+ @"The Phone Auth Credential was created with an empty SMS verification Code.";
+
+/** @var kFIRAuthErrorMessageInvalidVerificationCode
+ @brief Message for @c FIRAuthErrorCodeInvalidVerificationCode error code.
+ */
+static NSString *const kFIRAuthErrorMessageInvalidVerificationCode =
+ @"The SMS verification code used to create the phone auth credential is invalid. Please resend "
+ "the verification code sms and be sure use the verification code provided by the user.";
+
+/** @var kFIRAuthErrorMessageMissingVerificationID
+ @brief Message for @c FIRAuthErrorCodeInvalidVerificationID error code.
+ */
+static NSString *const kFIRAuthErrorMessageMissingVerificationID =
+ @"The Phone Auth Credential was created with an empty verification ID.";
+
+/** @var kFIRAuthErrorMessageInvalidVerificationID
+ @brief Message for @c FIRAuthErrorCodeInvalidVerificationID error code.
+ */
+static NSString *const kFIRAuthErrorMessageInvalidVerificationID =
+ @"The verification ID used to create the phone auth credential is invalid.";
+
+/** @var kFIRAuthErrorMessageSessionExpired
+ @brief Message for @c FIRAuthErrorCodeSessionExpired error code.
+ */
+static NSString *const kFIRAuthErrorMessageSessionExpired = @"The SMS code has expired. Please "
+ @"re-send the verification code to try again.";
+
+/** @var kFIRAuthErrorMessageMissingAppCredential
+ @brief Message for @c FIRAuthErrorCodeMissingAppCredential error code.
+ */
+static NSString *const kFIRAuthErrorMessageMissingAppCredential = @"The phone verification request "
+ "is missing an APNs Device token. Firebase Auth automatically detects APNs Device Tokens, "
+ "however, if method swizzling is disabled, the APNs token must be set via the APNSToken "
+ "property on FIRAuth or by calling setAPNSToken:type on FIRAuth.";
+
+/** @var kFIRAuthErrorMessageInvalidAppCredential
+ @brief Message for @c FIRAuthErrorCodeInvalidAppCredential error code.
+ */
+static NSString *const kFIRAuthErrorMessageInvalidAppCredential = @"The APNs device token provided "
+ "may be incorrect or does not match the private certificate uploaded to the Firebase Console.";
+
+/** @var kFIRAuthErrorMessageQuotaExceeded
+ @brief Message for @c FIRAuthErrorCodeQuotaExceeded error code.
+ */
+static NSString *const kFIRAuthErrorMessageQuotaExceeded = @"The SMS quota for this project has "
+ "been exceeded.";
+
+/** @var kFIRAuthErrorMessageMissingAppToken
+ @brief Message for @c FIRAuthErrorCodeMissingAppToken error code.
+ */
+static NSString *const kFIRAuthErrorMessageMissingAppToken = @"Remote notification and background "
+ "fetching need to be set up for the app. If app delegate swizzling is disabled, the APNs "
+ "device token received by UIApplicationDelegate needs to be forwarded to FIRAuth's APNSToken "
+ "property.";
+
+/** @var kFIRAuthErrorMessageMissingAppToken
+ @brief Message for @c FIRAuthErrorCodeMissingAppToken error code.
+ */
+static NSString *const kFIRAuthErrorMessageNotificationNotForwarded = @"If app delegate swizzling "
+ "is disabled, remote notifications received by UIApplicationDelegate need to be forwarded to "
+ "FIRAuth's canHandleNotificaton: method.";
+
+/** @var kFIRAuthErrorMessageAppNotVerified
+ @brief Message for @c FIRAuthErrorCodeMissingAppToken error code.
+ */
+static NSString *const kFIRAuthErrorMessageAppNotVerified = @"Firebase could not retrieve the "
+ "silent push notification and therefore could not verify your app. Ensure that you configured "
+ "your app correctly to recieve push notifications.";
+
+/** @var kFIRAuthErrorMessageInternalError
+ @brief Message for @c FIRAuthErrorCodeInternalError error code.
+ */
+static NSString *const kFIRAuthErrorMessageInternalError = @"An internal error has occurred, "
+ "print and inspect the error details for more information.";
+
+/** @var FIRAuthErrorDescription
+ @brief The error descrioption, based on the error code.
+ @remarks No default case so that we get a compiler warning if a new value was added to the enum.
+ */
+static NSString *FIRAuthErrorDescription(FIRAuthErrorCode code) {
+ switch (code) {
+ case FIRAuthErrorCodeInvalidCustomToken:
+ return kFIRAuthErrorMessageInvalidCustomToken;
+ case FIRAuthErrorCodeCustomTokenMismatch:
+ return kFIRAuthErrorMessageCustomTokenMismatch;
+ case FIRAuthErrorCodeInvalidEmail:
+ return kFIRAuthErrorMessageInvalidEmail;
+ case FIRAuthErrorCodeInvalidCredential:
+ return kFIRAuthErrorMessageInvalidCredential;
+ case FIRAuthErrorCodeUserDisabled:
+ return kFIRAuthErrorMessageUserDisabled;
+ case FIRAuthErrorCodeEmailAlreadyInUse:
+ return kFIRAuthErrorMessageEmailAlreadyInUse;
+ case FIRAuthErrorCodeWrongPassword:
+ return kFIRAuthErrorMessageWrongPassword;
+ case FIRAuthErrorCodeTooManyRequests:
+ return kFIRAuthErrorMessageTooManyRequests;
+ case FIRAuthErrorCodeAccountExistsWithDifferentCredential:
+ return kFIRAuthErrorMessageAccountExistsWithDifferentCredential;
+ case FIRAuthErrorCodeRequiresRecentLogin:
+ return kFIRAuthErrorMessageRequiresRecentLogin;
+ case FIRAuthErrorCodeProviderAlreadyLinked:
+ return kFIRAuthErrorMessageProviderAlreadyLinked;
+ case FIRAuthErrorCodeNoSuchProvider:
+ return kFIRAuthErrorMessageNoSuchProvider;
+ case FIRAuthErrorCodeInvalidUserToken:
+ return kFIRAuthErrorMessageInvalidUserToken;
+ case FIRAuthErrorCodeNetworkError:
+ return kFIRAuthErrorMessageNetworkError;
+ case FIRAuthErrorCodeKeychainError:
+ return kFIRAuthErrorMessageKeychainError;
+ case FIRAuthErrorCodeUserTokenExpired:
+ return kFIRAuthErrorMessageUserTokenExpired;
+ case FIRAuthErrorCodeUserNotFound:
+ return kFIRAuthErrorMessageUserNotFound;
+ case FIRAuthErrorCodeInvalidAPIKey:
+ return kFIRAuthErrorMessageInvalidAPIKey;
+ case FIRAuthErrorCodeCredentialAlreadyInUse:
+ return kFIRAuthErrorMessageCredentialAlreadyInUse;
+ case FIRAuthErrorCodeInternalError:
+ return kFIRAuthErrorMessageInternalError;
+ case FIRAuthErrorCodeUserMismatch:
+ return FIRAuthErrorMessageUserMismatch;
+ case FIRAuthErrorCodeOperationNotAllowed:
+ return kFIRAuthErrorMessageOperationNotAllowed;
+ case FIRAuthErrorCodeWeakPassword:
+ return kFIRAuthErrorMessageWeakPassword;
+ case FIRAuthErrorCodeAppNotAuthorized:
+ return kFIRAuthErrorMessageAppNotAuthorized;
+ case FIRAuthErrorCodeExpiredActionCode:
+ return kFIRAuthErrorMessageExpiredActionCode;
+ case FIRAuthErrorCodeInvalidActionCode:
+ return kFIRAuthErrorMessageInvalidActionCode;
+ case FIRAuthErrorCodeInvalidSender:
+ return kFIRAuthErrorMessageInvalidSender;
+ case FIRAuthErrorCodeInvalidMessagePayload:
+ return kFIRAuthErrorMessageInvalidMessagePayload;
+ case FIRAuthErrorCodeInvalidRecipientEmail:
+ return kFIRAuthErrorMessageInvalidRecipientEmail;
+ case FIRAuthErrorCodeMissingPhoneNumber:
+ return kFIRAuthErrorMessageMissingPhoneNumber;
+ case FIRAuthErrorCodeInvalidPhoneNumber:
+ return kFIRAuthErrorMessageInvalidPhoneNumber;
+ case FIRAuthErrorCodeMissingVerificationCode:
+ return kFIRAuthErrorMessageMissingVerificationCode;
+ case FIRAuthErrorCodeInvalidVerificationCode:
+ return kFIRAuthErrorMessageInvalidVerificationCode;
+ case FIRAuthErrorCodeMissingVerificationID:
+ return kFIRAuthErrorMessageMissingVerificationID;
+ case FIRAuthErrorCodeInvalidVerificationID:
+ return kFIRAuthErrorMessageInvalidVerificationID;
+ case FIRAuthErrorCodeSessionExpired:
+ return kFIRAuthErrorMessageSessionExpired;
+ case FIRAuthErrorCodeMissingAppCredential:
+ return kFIRAuthErrorMessageMissingAppCredential;
+ case FIRAuthErrorCodeInvalidAppCredential:
+ return kFIRAuthErrorMessageInvalidAppCredential;
+ case FIRAuthErrorCodeQuotaExceeded:
+ return kFIRAuthErrorMessageQuotaExceeded;
+ case FIRAuthErrorCodeMissingAppToken:
+ return kFIRAuthErrorMessageMissingAppToken;
+ case FIRAuthErrorCodeNotificationNotForwarded:
+ return kFIRAuthErrorMessageNotificationNotForwarded;
+ case FIRAuthErrorCodeAppNotVerified:
+ return kFIRAuthErrorMessageAppNotVerified;
+ }
+}
+
+/** @var FIRAuthErrorCodeString
+ @brief The the error short string, based on the error code.
+ @remarks No default case so that we get a compiler warning if a new value was added to the enum.
+ */
+static NSString *const FIRAuthErrorCodeString(FIRAuthErrorCode code) {
+ switch (code) {
+ case FIRAuthErrorCodeInvalidCustomToken:
+ return @"ERROR_INVALID_CUSTOM_TOKEN";
+ case FIRAuthErrorCodeCustomTokenMismatch:
+ return @"ERROR_CUSTOM_TOKEN_MISMATCH";
+ case FIRAuthErrorCodeInvalidEmail:
+ return @"ERROR_INVALID_EMAIL";
+ case FIRAuthErrorCodeInvalidCredential:
+ return @"ERROR_INVALID_CREDENTIAL";
+ case FIRAuthErrorCodeUserDisabled:
+ return @"ERROR_USER_DISABLED";
+ case FIRAuthErrorCodeEmailAlreadyInUse:
+ return @"ERROR_EMAIL_ALREADY_IN_USE";
+ case FIRAuthErrorCodeWrongPassword:
+ return @"ERROR_WRONG_PASSWORD";
+ case FIRAuthErrorCodeTooManyRequests:
+ return @"ERROR_TOO_MANY_REQUESTS";
+ case FIRAuthErrorCodeAccountExistsWithDifferentCredential:
+ return @"ERROR_ACCOUNT_EXISTS_WITH_DIFFERENT_CREDENTIAL";
+ case FIRAuthErrorCodeRequiresRecentLogin:
+ return @"ERROR_REQUIRES_RECENT_LOGIN";
+ case FIRAuthErrorCodeProviderAlreadyLinked:
+ return @"ERROR_PROVIDER_ALREADY_LINKED";
+ case FIRAuthErrorCodeNoSuchProvider:
+ return @"ERROR_NO_SUCH_PROVIDER";
+ case FIRAuthErrorCodeInvalidUserToken:
+ return @"ERROR_INVALID_USER_TOKEN";
+ case FIRAuthErrorCodeNetworkError:
+ return @"ERROR_NETWORK_REQUEST_FAILED";
+ case FIRAuthErrorCodeKeychainError:
+ return @"ERROR_KEYCHAIN_ERROR";
+ case FIRAuthErrorCodeUserTokenExpired:
+ return @"ERROR_USER_TOKEN_EXPIRED";
+ case FIRAuthErrorCodeUserNotFound:
+ return @"ERROR_USER_NOT_FOUND";
+ case FIRAuthErrorCodeInvalidAPIKey:
+ return @"ERROR_INVALID_API_KEY";
+ case FIRAuthErrorCodeCredentialAlreadyInUse:
+ return @"ERROR_CREDENTIAL_ALREADY_IN_USE";
+ case FIRAuthErrorCodeInternalError:
+ return @"ERROR_INTERNAL_ERROR";
+ case FIRAuthErrorCodeUserMismatch:
+ return @"ERROR_USER_MISMATCH";
+ case FIRAuthErrorCodeOperationNotAllowed:
+ return @"ERROR_OPERATION_NOT_ALLOWED";
+ case FIRAuthErrorCodeWeakPassword:
+ return @"ERROR_WEAK_PASSWORD";
+ case FIRAuthErrorCodeAppNotAuthorized:
+ return @"ERROR_APP_NOT_AUTHORIZED";
+ case FIRAuthErrorCodeExpiredActionCode:
+ return @"ERROR_EXPIRED_ACTION_CODE";
+ case FIRAuthErrorCodeInvalidActionCode:
+ return @"ERROR_INVALID_ACTION_CODE";
+ case FIRAuthErrorCodeInvalidMessagePayload:
+ return @"ERROR_INVALID_MESSAGE_PAYLOAD";
+ case FIRAuthErrorCodeInvalidSender:
+ return @"ERROR_INVALID_SENDER";
+ case FIRAuthErrorCodeInvalidRecipientEmail:
+ return @"ERROR_INVALID_RECIPIENT_EMAIL";
+ case FIRAuthErrorCodeMissingPhoneNumber:
+ return @"ERROR_MISSING_PHONE_NUMBER";
+ case FIRAuthErrorCodeInvalidPhoneNumber:
+ return @"ERROR_INVALID_PHONE_NUMBER";
+ case FIRAuthErrorCodeMissingVerificationCode:
+ return @"ERROR_MISSING_VERIFICATION_CODE";
+ case FIRAuthErrorCodeInvalidVerificationCode:
+ return @"ERROR_INVALID_VERIFICATION_CODE";
+ case FIRAuthErrorCodeMissingVerificationID:
+ return @"ERROR_MISSING_VERIFICATION_ID";
+ case FIRAuthErrorCodeInvalidVerificationID:
+ return @"ERROR_INVALID_VERIFICATION_ID";
+ case FIRAuthErrorCodeSessionExpired:
+ return @"ERROR_SESSION_EXPIRED";
+ case FIRAuthErrorCodeMissingAppCredential:
+ return @"MISSING_APP_CREDENTIAL";
+ case FIRAuthErrorCodeInvalidAppCredential:
+ return @"INVALID_APP_CREDENTIAL";
+ case FIRAuthErrorCodeQuotaExceeded:
+ return @"ERROR_QUOTA_EXCEEDED";
+ case FIRAuthErrorCodeMissingAppToken:
+ return @"ERROR_MISSING_APP_TOKEN";
+ case FIRAuthErrorCodeNotificationNotForwarded:
+ return @"ERROR_NOTIFICATION_NOT_FORWARDED";
+ case FIRAuthErrorCodeAppNotVerified:
+ return @"ERROR_APP_NOT_VERIFIED";
+ }
+}
+
+@implementation FIRAuthErrorUtils
+
++ (NSError *)errorWithCode:(FIRAuthInternalErrorCode)code {
+ return [self errorWithCode:code message:nil];
+}
+
++ (NSError *)errorWithCode:(FIRAuthInternalErrorCode)code
+ message:(nullable NSString *)message {
+ NSDictionary *userInfo = nil;
+ if (message.length) {
+ userInfo = @{
+ NSLocalizedDescriptionKey : message
+ };
+ }
+ return [self errorWithCode:code userInfo:userInfo];
+}
+
++ (NSError *)errorWithCode:(FIRAuthInternalErrorCode)code
+ underlyingError:(nullable NSError *)underlyingError {
+ NSDictionary *errorUserInfo = nil;
+ if (underlyingError) {
+ errorUserInfo = @{
+ NSUnderlyingErrorKey : underlyingError
+ };
+ }
+ return [self errorWithCode:code userInfo:errorUserInfo];
+}
+
++ (NSError *)errorWithCode:(FIRAuthInternalErrorCode)code userInfo:(NSDictionary *)userInfo {
+ BOOL isPublic = (code & FIRAuthPublicErrorCodeFlag) == FIRAuthPublicErrorCodeFlag;
+ if (isPublic) {
+ // This is a public error. Return it as a public error and add a description.
+ NSInteger errorCode = code & ~FIRAuthPublicErrorCodeFlag;
+ NSMutableDictionary *errorUserInfo = [NSMutableDictionary dictionaryWithDictionary:userInfo];
+ if (!errorUserInfo[NSLocalizedDescriptionKey]) {
+ errorUserInfo[NSLocalizedDescriptionKey] = FIRAuthErrorDescription(errorCode);
+ }
+ errorUserInfo[FIRAuthErrorNameKey] = FIRAuthErrorCodeString(errorCode);
+ return [NSError errorWithDomain:FIRAuthErrorDomain code:errorCode userInfo:errorUserInfo];
+ } else {
+ // This is an internal error. Wrap it in an internal error.
+ NSError *error =
+ [NSError errorWithDomain:FIRAuthInternalErrorDomain code:code userInfo:userInfo];
+ return [self errorWithCode:FIRAuthInternalErrorCodeInternalError underlyingError:error];
+ }
+}
+
++ (NSError *)RPCRequestEncodingErrorWithUnderlyingError:(NSError *)underlyingError {
+ return [self errorWithCode:FIRAuthInternalErrorCodeRPCRequestEncodingError
+ underlyingError:underlyingError];
+}
+
++ (NSError *)JSONSerializationErrorForUnencodableType {
+ return [self errorWithCode:FIRAuthInternalErrorCodeJSONSerializationError];
+}
+
++ (NSError *)JSONSerializationErrorWithUnderlyingError:(NSError *)underlyingError {
+ return [self errorWithCode:FIRAuthInternalErrorCodeJSONSerializationError
+ underlyingError:underlyingError];
+}
+
++ (NSError *)networkErrorWithUnderlyingError:(NSError *)underlyingError {
+ return [self errorWithCode:FIRAuthInternalErrorCodeNetworkError
+ underlyingError:underlyingError];
+}
+
++ (NSError *)unexpectedErrorResponseWithData:(NSData *)data
+ underlyingError:(NSError *)underlyingError {
+ return [self errorWithCode:FIRAuthInternalErrorCodeUnexpectedErrorResponse userInfo:@{
+ FIRAuthErrorUserInfoDataKey : data,
+ NSUnderlyingErrorKey : underlyingError
+ }];
+}
+
++ (NSError *)unexpectedErrorResponseWithDeserializedResponse:(id)deserializedResponse {
+ return [self errorWithCode:FIRAuthInternalErrorCodeUnexpectedErrorResponse userInfo:@{
+ FIRAuthErrorUserInfoDeserializedResponseKey : deserializedResponse
+ }];
+}
+
++ (NSError *)unexpectedResponseWithData:(NSData *)data
+ underlyingError:(NSError *)underlyingError {
+ return [self errorWithCode:FIRAuthInternalErrorCodeUnexpectedResponse userInfo:@{
+ FIRAuthErrorUserInfoDataKey : data,
+ NSUnderlyingErrorKey : underlyingError
+ }];
+}
+
++ (NSError *)unexpectedResponseWithDeserializedResponse:(id)deserializedResponse {
+ return [self errorWithCode:FIRAuthInternalErrorCodeUnexpectedResponse userInfo:@{
+ FIRAuthErrorUserInfoDeserializedResponseKey : deserializedResponse
+ }];
+}
+
++ (NSError *)unexpectedResponseWithDeserializedResponse:(nullable id)deserializedResponse
+ underlyingError:(NSError *)underlyingError {
+ NSMutableDictionary *userInfo =
+ [NSMutableDictionary dictionaryWithDictionary:@{ NSUnderlyingErrorKey : underlyingError }];
+ if (deserializedResponse) {
+ userInfo[FIRAuthErrorUserInfoDeserializedResponseKey] = deserializedResponse;
+ }
+ return [self errorWithCode:FIRAuthInternalErrorCodeUnexpectedResponse userInfo:userInfo];
+}
+
++ (NSError *)RPCResponseDecodingErrorWithDeserializedResponse:(id)deserializedResponse
+ underlyingError:(NSError *)underlyingError {
+ return [self errorWithCode:FIRAuthInternalErrorCodeRPCResponseDecodingError userInfo:@{
+ FIRAuthErrorUserInfoDeserializedResponseKey : deserializedResponse,
+ NSUnderlyingErrorKey : underlyingError
+ }];
+}
+
++ (NSError *)emailAlreadyInUseErrorWithEmail:(nullable NSString *)email {
+ NSMutableDictionary *userInfo = [[NSMutableDictionary alloc] init];
+ if (email.length) {
+ userInfo[FIRAuthErrorUserInfoEmailKey] = email;
+ }
+ return [self errorWithCode:FIRAuthInternalErrorCodeEmailAlreadyInUse userInfo:userInfo];
+}
+
++ (NSError *)userDisabledErrorWithMessage:(nullable NSString *)message {
+ return [self errorWithCode:FIRAuthInternalErrorCodeUserDisabled message:message];
+}
+
++ (NSError *)wrongPasswordErrorWithMessage:(nullable NSString *)message {
+ return [self errorWithCode:FIRAuthInternalErrorCodeWrongPassword message:message];
+}
+
++ (NSError *)tooManyRequestsErrorWithMessage:(nullable NSString *)message {
+ return [self errorWithCode:FIRAuthInternalErrorCodeTooManyRequests message:message];
+}
+
++ (NSError *)invalidCustomTokenErrorWithMessage:(nullable NSString *)message {
+ return [self errorWithCode:FIRAuthInternalErrorCodeInvalidCustomToken message:message];
+}
+
++ (NSError *)customTokenMistmatchErrorWithMessage:(nullable NSString *)message {
+ return [self errorWithCode:FIRAuthInternalErrorCodeCustomTokenMismatch message:message];
+}
+
++ (NSError *)invalidCredentialErrorWithMessage:(nullable NSString *)message {
+ return [self errorWithCode:FIRAuthInternalErrorCodeInvalidCredential message:message];
+}
+
++ (NSError *)requiresRecentLoginErrorWithMessage:(nullable NSString *)message {
+ return [self errorWithCode:FIRAuthInternalErrorCodeRequiresRecentLogin message:message];
+}
+
++ (NSError *)invalidUserTokenErrorWithMessage:(nullable NSString *)message {
+ return [self errorWithCode:FIRAuthInternalErrorCodeInvalidUserToken message:message];
+}
+
++ (NSError *)invalidEmailErrorWithMessage:(nullable NSString *)message {
+ return [self errorWithCode:FIRAuthInternalErrorCodeInvalidEmail message:message];
+}
+
++ (NSError *)accountExistsWithDifferentCredentialErrorWithEmail:(nullable NSString *)email {
+ return [self errorWithCode:FIRAuthInternalErrorCodeAccountExistsWithDifferentCredential
+ userInfo:@{ FIRAuthErrorUserInfoEmailKey : email }];
+}
+
++ (NSError *)providerAlreadyLinkedError {
+ return [self errorWithCode:FIRAuthInternalErrorCodeProviderAlreadyLinked];
+}
+
++ (NSError *)noSuchProviderError {
+ return [self errorWithCode:FIRAuthInternalErrorCodeNoSuchProvider];
+}
+
++ (NSError *)userTokenExpiredErrorWithMessage:(nullable NSString *)message {
+ return [self errorWithCode:FIRAuthInternalErrorCodeUserTokenExpired message:message];
+}
+
++ (NSError *)userNotFoundErrorWithMessage:(nullable NSString *)message {
+ return [self errorWithCode:FIRAuthInternalErrorCodeUserNotFound message:message];
+}
+
++ (NSError *)invalidAPIKeyError {
+ return [self errorWithCode:FIRAuthInternalErrorCodeInvalidAPIKey];
+}
+
++ (NSError *)userMismatchError {
+ return [self errorWithCode:FIRAuthInternalErrorCodeUserMismatch];
+}
+
++ (NSError *)credentialAlreadyInUseErrorWithMessage:(nullable NSString *)message
+ credential:(nullable FIRPhoneAuthCredential *)credential {
+ if (credential) {
+ return [self errorWithCode:FIRAuthInternalErrorCodeCredentialAlreadyInUse
+ userInfo:@{ FIRAuthUpdatedCredentialKey : credential }];
+ }
+ return [self errorWithCode:FIRAuthInternalErrorCodeCredentialAlreadyInUse message:message];
+}
+
++ (NSError *)operationNotAllowedErrorWithMessage:(nullable NSString *)message {
+ return [self errorWithCode:FIRAuthInternalErrorCodeOperationNotAllowed message:message];
+}
+
++ (NSError *)weakPasswordErrorWithServerResponseReason:(NSString *)reason {
+ return [self errorWithCode:FIRAuthInternalErrorCodeWeakPassword userInfo:@{
+ NSLocalizedFailureReasonErrorKey : reason
+ }];
+}
+
++ (NSError *)appNotAuthorizedError {
+ return [self errorWithCode:FIRAuthInternalErrorCodeAppNotAuthorized];
+}
+
++ (NSError *)expiredActionCodeErrorWithMessage:(nullable NSString *)message {
+ return [self errorWithCode:FIRAuthInternalErrorCodeExpiredActionCode message:message];
+}
+
++ (NSError *)invalidActionCodeErrorWithMessage:(nullable NSString *)message {
+ return [self errorWithCode:FIRAuthInternalErrorCodeInvalidActionCode message:message];
+}
+
++ (NSError *)invalidMessagePayloadErrorWithMessage:(nullable NSString *)message {
+ return [self errorWithCode:FIRAuthInternalErrorCodeInvalidMessagePayload message:message];
+}
+
++ (NSError *)invalidSenderErrorWithMessage:(nullable NSString *)message {
+ return [self errorWithCode:FIRAuthInternalErrorCodeInvalidSender message:message];
+}
+
++ (NSError *)invalidRecipientEmailErrorWithMessage:(nullable NSString *)message {
+ return [self errorWithCode:FIRAuthInternalErrorCodeInvalidRecipientEmail message:message];
+}
+
++ (NSError *)missingPhoneNumberErrorWithMessage:(nullable NSString *)message {
+ return [self errorWithCode:FIRAuthInternalErrorCodeMissingPhoneNumber message:message];
+}
+
++ (NSError *)invalidPhoneNumberErrorWithMessage:(nullable NSString *)message {
+ return [self errorWithCode:FIRAuthInternalErrorCodeInvalidPhoneNumber message:message];
+}
+
++ (NSError *)missingVerificationCodeErrorWithMessage:(nullable NSString *)message {
+ return [self errorWithCode:FIRAuthInternalErrorCodeMissingVerificationCode message:message];
+}
+
++ (NSError *)invalidVerificationCodeErrorWithMessage:(nullable NSString *)message {
+ return [self errorWithCode:FIRAuthInternalErrorCodeInvalidVerificationCode message:message];
+}
+
++ (NSError *)missingVerificationIDErrorWithMessage:(nullable NSString *)message {
+ return [self errorWithCode:FIRAuthInternalErrorCodeMissingVerificationID message:message];
+}
+
++ (NSError *)invalidVerificationIDErrorWithMessage:(nullable NSString *)message {
+ return [self errorWithCode:FIRAuthInternalErrorCodeInvalidVerificationID message:message];
+}
+
++ (NSError *)sessionExpiredErrorWithMessage:(nullable NSString *)message {
+ return [self errorWithCode:FIRAuthInternalErrorCodeSessionExpired message:message];
+}
+
++ (NSError *)missingAppCredentialWithMessage:(nullable NSString *)message {
+ return [self errorWithCode:FIRAuthInternalErrorCodeMissingAppCredential message:message];
+}
+
++ (NSError *)invalidAppCredentialWithMessage:(nullable NSString *)message {
+ return [self errorWithCode:FIRAuthInternalErrorCodeInvalidAppCredential message:message];
+}
+
++ (NSError *)quotaExceededErrorWithMessage:(nullable NSString *)message {
+ return [self errorWithCode:FIRAuthInternalErrorCodeQuotaExceeded message:message];
+}
+
++ (NSError *)missingAppTokenError {
+ return [self errorWithCode:FIRAuthInternalErrorCodeMissingAppToken];
+}
+
++ (NSError *)notificationNotForwardedError {
+ return [self errorWithCode:FIRAuthInternalErrorCodeNotificationNotForwarded];
+}
+
++ (NSError *)appNotVerifiedErrorWithMessage:(nullable NSString *)message {
+ return [self errorWithCode:FIRAuthInternalErrorCodeAppNotVerified message:message];
+}
+
++ (NSError *)keychainErrorWithFunction:(NSString *)keychainFunction status:(OSStatus)status {
+ NSString *failureReason = [NSString stringWithFormat:@"%@ (%li)", keychainFunction, (long)status];
+ return [self errorWithCode:FIRAuthInternalErrorCodeKeychainError userInfo:@{
+ NSLocalizedFailureReasonErrorKey : failureReason,
+ }];
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/FIRAuthErrors.h b/Firebase/Auth/Source/FIRAuthErrors.h
new file mode 100644
index 0000000..c1e7900
--- /dev/null
+++ b/Firebase/Auth/Source/FIRAuthErrors.h
@@ -0,0 +1,258 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "FIRAuthSwiftNameSupport.h"
+
+/** @class FIRAuthErrors
+ @remarks Error Codes common to all API Methods:
+ <ul>
+ <li>@c FIRAuthErrorCodeNetworkError</li>
+ <li>@c FIRAuthErrorCodeUserNotFound</li>
+ <li>@c FIRAuthErrorCodeUserTokenExpired</li>
+ <li>@c FIRAuthErrorCodeTooManyRequests</li>
+ <li>@c FIRAuthErrorCodeInvalidAPIKey</li>
+ <li>@c FIRAuthErrorCodeAppNotAuthorized</li>
+ <li>@c FIRAuthErrorCodeKeychainError</li>
+ <li>@c FIRAuthErrorCodeInternalError</li>
+ </ul>
+ @remarks Common error codes for @c FIRUser operations:
+ <ul>
+ <li>@c FIRAuthErrorCodeInvalidUserToken</li>
+ <li>@c FIRAuthErrorCodeUserDisabled</li>
+ </ul>
+ */
+FIR_SWIFT_NAME(AuthErrors)
+@interface FIRAuthErrors
+
+/**
+ @brief The Firebase Auth error domain.
+ */
+extern NSString *const FIRAuthErrorDomain FIR_SWIFT_NAME(AuthErrorDomain);
+
+/**
+ @brief The key used to read the updated credential from the userinfo dictionary of the NSError
+ object returned in the case that the credential being linked in already in use.
+ */
+extern NSString *const FIRAuthUpdatedCredentialKey FIR_SWIFT_NAME(AuthUpdatedCredentialKey);
+
+/**
+ @brief The name of the key for the "error_name" string in the NSError userinfo dictionary.
+ */
+extern NSString *const FIRAuthErrorNameKey FIR_SWIFT_NAME(AuthErrorNameKey);
+
+/** @var FIRAuthErrorUserInfoEmailKey
+ @brief Errors with the code @c FIRAuthErrorCodeEmailAlreadyInUse may contains an
+ @c NSError.userInfo dictinary which contains this key. The value associated with this key is
+ an NSString of the email address that already exists.
+ */
+extern NSString *const FIRAuthErrorUserInfoEmailKey FIR_SWIFT_NAME(AuthErrorUserInfoEmailKey);
+
+/**
+ @brief Error codes used by Firebase Auth.
+ */
+typedef NS_ENUM(NSInteger, FIRAuthErrorCode) {
+ /** Indicates a validation error with the custom token.
+ */
+ FIRAuthErrorCodeInvalidCustomToken = 17000,
+
+ /** Indicates the service account and the API key belong to different projects.
+ */
+ FIRAuthErrorCodeCustomTokenMismatch = 17002,
+
+ /** Indicates the IDP token or requestUri is invalid.
+ */
+ FIRAuthErrorCodeInvalidCredential = 17004,
+
+ /** Indicates the user's account is disabled on the server.
+ */
+ FIRAuthErrorCodeUserDisabled = 17005,
+
+ /** Indicates the administrator disabled sign in with the specified identity provider.
+ */
+ FIRAuthErrorCodeOperationNotAllowed = 17006,
+
+ /** Indicates the email used to attempt a sign up is already in use.
+ */
+ FIRAuthErrorCodeEmailAlreadyInUse = 17007,
+
+ /** Indicates the email is invalid.
+ */
+ FIRAuthErrorCodeInvalidEmail = 17008,
+
+ /** Indicates the user attempted sign in with a wrong password.
+ */
+ FIRAuthErrorCodeWrongPassword = 17009,
+
+ /** Indicates that too many requests were made to a server method.
+ */
+ FIRAuthErrorCodeTooManyRequests = 17010,
+
+ /** Indicates the user account was not found.
+ */
+ FIRAuthErrorCodeUserNotFound = 17011,
+
+ /** Indicates account linking is required.
+ */
+ FIRAuthErrorCodeAccountExistsWithDifferentCredential = 17012,
+
+ /** Indicates the user has attemped to change email or password more than 5 minutes after
+ signing in.
+ */
+ FIRAuthErrorCodeRequiresRecentLogin = 17014,
+
+ /** Indicates an attempt to link a provider to which the account is already linked.
+ */
+ FIRAuthErrorCodeProviderAlreadyLinked = 17015,
+
+ /** Indicates an attempt to unlink a provider that is not linked.
+ */
+ FIRAuthErrorCodeNoSuchProvider = 17016,
+
+ /** Indicates user's saved auth credential is invalid, the user needs to sign in again.
+ */
+ FIRAuthErrorCodeInvalidUserToken = 17017,
+
+ /** Indicates a network error occurred (such as a timeout, interrupted connection, or
+ unreachable host). These types of errors are often recoverable with a retry. The @c
+ NSUnderlyingError field in the @c NSError.userInfo dictionary will contain the error
+ encountered.
+ */
+ FIRAuthErrorCodeNetworkError = 17020,
+
+ /** Indicates the saved token has expired, for example, the user may have changed account
+ password on another device. The user needs to sign in again on the device that made this
+ request.
+ */
+ FIRAuthErrorCodeUserTokenExpired = 17021,
+
+ /** Indicates an invalid API key was supplied in the request.
+ */
+ FIRAuthErrorCodeInvalidAPIKey = 17023,
+
+ /** Indicates that an attempt was made to reauthenticate with a user which is not the current
+ user.
+ */
+ FIRAuthErrorCodeUserMismatch = 17024,
+
+ /** Indicates an attempt to link with a credential that has already been linked with a
+ different Firebase account
+ */
+ FIRAuthErrorCodeCredentialAlreadyInUse = 17025,
+
+ /** Indicates an attempt to set a password that is considered too weak.
+ */
+ FIRAuthErrorCodeWeakPassword = 17026,
+
+ /** Indicates the App is not authorized to use Firebase Authentication with the
+ provided API Key.
+ */
+ FIRAuthErrorCodeAppNotAuthorized = 17028,
+
+ /** Indicates the OOB code is expired.
+ */
+ FIRAuthErrorCodeExpiredActionCode = 17029,
+
+ /** Indicates the OOB code is invalid.
+ */
+ FIRAuthErrorCodeInvalidActionCode = 17030,
+
+ /** Indicates that there are invalid parameters in the payload during a "send password reset
+ * email" attempt.
+ */
+ FIRAuthErrorCodeInvalidMessagePayload = 17031,
+
+ /** Indicates that the sender email is invalid during a "send password reset email" attempt.
+ */
+ FIRAuthErrorCodeInvalidSender = 17032,
+
+ /** Indicates that the recipient email is invalid.
+ */
+ FIRAuthErrorCodeInvalidRecipientEmail = 17033,
+
+ // The enum values between 17033 and 17041 are reserved and should NOT be used for new error
+ // codes.
+
+ /** Indicates that a phone number was not provided in a call to @c
+ verifyPhoneNumber:completion:.
+ */
+ FIRAuthErrorCodeMissingPhoneNumber = 17041,
+
+ /** Indicates that an invalid phone number was provided in a call to @c
+ verifyPhoneNumber:completion:.
+ */
+ FIRAuthErrorCodeInvalidPhoneNumber = 17042,
+
+ /** Indicates that the phone auth credential was created with an empty verification code.
+ */
+ FIRAuthErrorCodeMissingVerificationCode = 17043,
+
+ /** Indicates that an invalid verification code was used in the verifyPhoneNumber request.
+ */
+ FIRAuthErrorCodeInvalidVerificationCode = 17044,
+
+ /** Indicates that the phone auth credential was created with an empty verification ID.
+ */
+ FIRAuthErrorCodeMissingVerificationID = 17045,
+
+ /** Indicates that an invalid verification ID was used in the verifyPhoneNumber request.
+ */
+ FIRAuthErrorCodeInvalidVerificationID = 17046,
+
+ /** Indicates that the APNS device token is missing in the verifyClient request.
+ */
+ FIRAuthErrorCodeMissingAppCredential = 17047,
+
+ /** Indicates that an invalid APNS device token was used in the verifyClient request.
+ */
+ FIRAuthErrorCodeInvalidAppCredential = 17048,
+
+ // The enum values between 17048 and 17051 are reserved and should NOT be used for new error
+ // codes.
+
+ /** Indicates that the SMS code has expired.
+ */
+ FIRAuthErrorCodeSessionExpired = 17051,
+
+ /** Indicates that the quota of SMS messages for a given project has been exceeded.
+ */
+ FIRAuthErrorCodeQuotaExceeded = 17052,
+
+ /** Indicates that the APNs device token could not be obtained. The app may not have set up
+ remote notification correctly, or may fail to forward the APNs device token to FIRAuth
+ if app delegate swizzling is disabled.
+ */
+ FIRAuthErrorCodeMissingAppToken = 17053,
+
+ /** Indicates that the app fails to forward remote notification to FIRAuth.
+ */
+ FIRAuthErrorCodeNotificationNotForwarded = 17054,
+
+ /** Indicates that the app could not be verified by Firebase during phone number authentication.
+ */
+ FIRAuthErrorCodeAppNotVerified = 17055,
+
+ /** Indicates an error occurred while attempting to access the keychain.
+ */
+ FIRAuthErrorCodeKeychainError = 17995,
+
+ /** Indicates an internal error occurred.
+ */
+ FIRAuthErrorCodeInternalError = 17999,
+} FIR_SWIFT_NAME(AuthErrorCode);
+
+@end
diff --git a/Firebase/Auth/Source/FIRAuthExceptionUtils.h b/Firebase/Auth/Source/FIRAuthExceptionUtils.h
new file mode 100644
index 0000000..3ae9159
--- /dev/null
+++ b/Firebase/Auth/Source/FIRAuthExceptionUtils.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @class FIRAuthExceptionUtils
+ @brief Utility class used to raise standardized Auth related exceptions.
+*/
+@interface FIRAuthExceptionUtils : NSObject
+
+/** @fn raiseInvalidParameterExceptionWithReason:
+ @brief raises the "invalid parameter" exception
+ @param reason string will contain a description of the error.
+ */
++ (void)raiseInvalidParameterExceptionWithReason:(nullable NSString *)reason;
+
+/** @fn raiseMethodNotImplementedExceptionWithReason:
+ @brief raises the "method not implemented" exception
+ @param reason string will contain a description of the error.
+ @see FIRMethodNotImplementedException
+ */
++ (void)raiseMethodNotImplementedExceptionWithReason:(nullable NSString *)reason;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/FIRAuthExceptionUtils.m b/Firebase/Auth/Source/FIRAuthExceptionUtils.m
new file mode 100644
index 0000000..0adcd34
--- /dev/null
+++ b/Firebase/Auth/Source/FIRAuthExceptionUtils.m
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRAuthExceptionUtils.h"
+
+/** @var FIRMethodNotImplementedException
+ @brief The name of the "Method Not Implemented" exception.
+ */
+static NSString *const FIRMethodNotImplementedException = @"FIRMethodNotImplementedException";
+
+@implementation FIRAuthExceptionUtils
+
++ (void)raiseInvalidParameterExceptionWithReason:(NSString *)reason {
+ [NSException raise:NSInvalidArgumentException format:@"%@", reason];
+}
+
++ (void)raiseMethodNotImplementedExceptionWithReason:(nullable NSString *)reason {
+ NSException *exception =
+ [NSException exceptionWithName:FIRMethodNotImplementedException reason:reason userInfo:nil];
+ [exception raise];
+}
+
+@end
diff --git a/Firebase/Auth/Source/FIRAuthGlobalWorkQueue.m b/Firebase/Auth/Source/FIRAuthGlobalWorkQueue.m
new file mode 100644
index 0000000..8780959
--- /dev/null
+++ b/Firebase/Auth/Source/FIRAuthGlobalWorkQueue.m
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "Private/FIRAuthGlobalWorkQueue.h"
+
+dispatch_queue_t FIRAuthGlobalWorkQueue() {
+ static dispatch_once_t once;
+ static dispatch_queue_t queue;
+ dispatch_once(&once, ^{
+ queue = dispatch_queue_create("com.google.firebase.auth.globalWorkQueue", NULL);
+ });
+ return queue;
+}
diff --git a/Firebase/Auth/Source/FIRAuthKeychain.m b/Firebase/Auth/Source/FIRAuthKeychain.m
new file mode 100644
index 0000000..68cf2f2
--- /dev/null
+++ b/Firebase/Auth/Source/FIRAuthKeychain.m
@@ -0,0 +1,256 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "Private/FIRAuthKeychain.h"
+
+#import <Security/Security.h>
+
+#import "Private/FIRAuthErrorUtils.h"
+#import "Private/FIRAuthUserDefaultsStorage.h"
+
+#if FIRAUTH_USER_DEFAULTS_STORAGE_AVAILABLE
+#import <UIKit/UIKit.h>
+
+/** @var kOSVersionMatcherForUsingUserDefaults
+ @brief The regular expression to match all OS versions that @c FIRAuthUserDefaultsStorage is
+ used instead if available.
+ */
+static NSString *const kOSVersionMatcherForUsingUserDefaults = @"^10\\.[01](\\..*)?$";
+
+#endif // FIRAUTH_USER_DEFAULTS_STORAGE_AVAILABLE
+
+/** @var kAccountPrefix
+ @brief The prefix string for keychain item account attribute before the key.
+ @remarks A number "1" is encoded in the prefix in case we need to upgrade the scheme in future.
+ */
+static NSString *const kAccountPrefix = @"firebase_auth_1_";
+
+@implementation FIRAuthKeychain {
+ /** @var _service
+ @brief The name of the keychain service.
+ */
+ NSString *_service;
+
+ /** @var _legacyItemDeletedForKey
+ @brief Indicates whether or not this class knows that the legacy item for a particular key has
+ been deleted.
+ @remarks This dictionary is to avoid unecessary keychain operations against legacy items.
+ */
+ NSMutableDictionary *_legacyEntryDeletedForKey;
+}
+
+- (id<FIRAuthStorage>)initWithService:(NSString *)service {
+
+#if FIRAUTH_USER_DEFAULTS_STORAGE_AVAILABLE
+
+ NSString *OSVersion = [UIDevice currentDevice].systemVersion;
+ NSRegularExpression *regex =
+ [NSRegularExpression regularExpressionWithPattern:kOSVersionMatcherForUsingUserDefaults
+ options:0
+ error:NULL];
+ if ([regex numberOfMatchesInString:OSVersion options:0 range:NSMakeRange(0, OSVersion.length)]) {
+ return (id<FIRAuthStorage>)[[FIRAuthUserDefaultsStorage alloc] initWithService:service];
+ }
+
+#endif // FIRAUTH_USER_DEFAULTS_STORAGE_AVAILABLE
+
+ self = [super init];
+ if (self) {
+ _service = [service copy];
+ _legacyEntryDeletedForKey = [[NSMutableDictionary alloc] init];
+ }
+ return self;
+}
+
+- (NSData *)dataForKey:(NSString *)key error:(NSError **_Nullable)error {
+ if (!key.length) {
+ [NSException raise:NSInvalidArgumentException
+ format:@"%@", @"The key cannot be nil or empty."];
+ return nil;
+ }
+ NSData *data = [self itemWithQuery:[self genericPasswordQueryWithKey:key] error:error];
+ if (error && *error) {
+ return nil;
+ }
+ if (data) {
+ return data;
+ }
+ // Check for legacy form.
+ if (_legacyEntryDeletedForKey[key]) {
+ return nil;
+ }
+ data = [self itemWithQuery:[self legacyGenericPasswordQueryWithKey:key] error:error];
+ if (error && *error) {
+ return nil;
+ }
+ if (!data) {
+ // Mark legacy data as non-existing so we don't have to query it again.
+ _legacyEntryDeletedForKey[key] = @YES;
+ return nil;
+ }
+ // Move the data to current form.
+ if (![self setData:data forKey:key error:error]) {
+ return nil;
+ }
+ [self deleteLegacyItemWithKey:key];
+ return data;
+}
+
+- (BOOL)setData:(NSData *)data forKey:(NSString *)key error:(NSError **_Nullable)error {
+ if (!key.length) {
+ [NSException raise:NSInvalidArgumentException
+ format:@"%@", @"The key cannot be nil or empty."];
+ return NO;
+ }
+ NSDictionary *attributes = @{
+ (__bridge id)kSecValueData : data,
+ (__bridge id)kSecAttrAccessible : (__bridge id)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly,
+ };
+ return [self setItemWithQuery:[self genericPasswordQueryWithKey:key]
+ attributes:attributes
+ error:error];
+}
+
+- (BOOL)removeDataForKey:(NSString *)key error:(NSError **_Nullable)error {
+ if (!key.length) {
+ [NSException raise:NSInvalidArgumentException
+ format:@"%@", @"The key cannot be nil or empty."];
+ return NO;
+ }
+ if (![self deleteItemWithQuery:[self genericPasswordQueryWithKey:key] error:error]) {
+ return NO;
+ }
+ // Legacy form item, if exists, also needs to be removed, otherwise it will be exposed when
+ // current form item is removed, leading to incorrect semantics.
+ [self deleteLegacyItemWithKey:key];
+ return YES;
+}
+
+#pragma mark - Private
+
+- (NSData *)itemWithQuery:(NSDictionary *)query error:(NSError **_Nullable)error {
+ NSMutableDictionary *returningQuery = [query mutableCopy];
+ returningQuery[(__bridge id)kSecReturnData] = @YES;
+ returningQuery[(__bridge id)kSecReturnAttributes] = @YES;
+ // Using a match limit of 2 means that we can check whether there is more than one item.
+ // If we used a match limit of 1 we would never find out.
+ returningQuery[(__bridge id)kSecMatchLimit] = @2;
+
+ CFArrayRef result = NULL;
+ OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)returningQuery,
+ (CFTypeRef *)&result);
+
+ if (status == noErr && result != NULL) {
+ NSArray *items = (__bridge_transfer NSArray *)result;
+ if (items.count != 1) {
+ if (error) {
+ *error = [FIRAuthErrorUtils keychainErrorWithFunction:@"SecItemCopyMatching"
+ status:status];
+ }
+ return nil;
+ }
+
+ if (error) {
+ *error = nil;
+ }
+ NSDictionary *item = items[0];
+ return item[(__bridge id)kSecValueData];
+ }
+
+ if (status == errSecItemNotFound) {
+ if (error) {
+ *error = nil;
+ }
+ } else {
+ if (error) {
+ *error = [FIRAuthErrorUtils keychainErrorWithFunction:@"SecItemCopyMatching" status:status];
+ }
+ }
+ return nil;
+}
+
+- (BOOL)setItemWithQuery:(NSDictionary *)query
+ attributes:(NSDictionary *)attributes
+ error:(NSError **_Nullable)error {
+ NSMutableDictionary *combined = [attributes mutableCopy];
+ [combined addEntriesFromDictionary:query];
+ BOOL hasItem = NO;
+ OSStatus status = SecItemAdd((__bridge CFDictionaryRef)combined, NULL);
+
+ if (status == errSecDuplicateItem) {
+ hasItem = YES;
+ status = SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)attributes);
+ }
+
+ if (status == noErr) {
+ return YES;
+ }
+ if (error) {
+ NSString *function = hasItem ? @"SecItemUpdate" : @"SecItemAdd";
+ *error = [FIRAuthErrorUtils keychainErrorWithFunction:function status:status];
+ }
+ return NO;
+}
+
+- (BOOL)deleteItemWithQuery:(NSDictionary *)query error:(NSError **_Nullable)error {
+ OSStatus status = SecItemDelete((__bridge CFDictionaryRef)query);
+ if (status == noErr || status == errSecItemNotFound) {
+ return YES;
+ }
+ if (error) {
+ *error = [FIRAuthErrorUtils keychainErrorWithFunction:@"SecItemDelete" status:status];
+ }
+ return NO;
+}
+
+/** @fn deleteLegacyItemsWithKey:
+ @brief Deletes legacy item from the keychain if it is not already known to be deleted.
+ @param key The key for the item.
+ */
+- (void)deleteLegacyItemWithKey:(NSString *)key {
+ if (_legacyEntryDeletedForKey[key]) {
+ return;
+ }
+ NSDictionary *query = [self legacyGenericPasswordQueryWithKey:key];
+ SecItemDelete((__bridge CFDictionaryRef)query);
+ _legacyEntryDeletedForKey[key] = @YES;
+}
+
+/** @fn genericPasswordQueryWithKey:
+ @brief Returns a keychain query of generic password to be used to manipulate key'ed value.
+ @param key The key for the value being manipulated, used as the account field in the query.
+ */
+- (NSDictionary *)genericPasswordQueryWithKey:(NSString *)key {
+ return @{
+ (__bridge id)kSecClass : (__bridge id)kSecClassGenericPassword,
+ (__bridge id)kSecAttrAccount : [kAccountPrefix stringByAppendingString:key],
+ (__bridge id)kSecAttrService : _service,
+ };
+}
+
+/** @fn legacyGenericPasswordQueryWithKey:
+ @brief Returns a keychain query of generic password without service field, which is used by
+ previous version of this class.
+ @param key The key for the value being manipulated, used as the account field in the query.
+ */
+- (NSDictionary *)legacyGenericPasswordQueryWithKey:(NSString *)key {
+ return @{
+ (__bridge id)kSecClass : (__bridge id)kSecClassGenericPassword,
+ (__bridge id)kSecAttrAccount : key,
+ };
+}
+
+@end
diff --git a/Firebase/Auth/Source/FIRAuthNotificationManager.m b/Firebase/Auth/Source/FIRAuthNotificationManager.m
new file mode 100644
index 0000000..0692562
--- /dev/null
+++ b/Firebase/Auth/Source/FIRAuthNotificationManager.m
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "Private/FIRAuthNotificationManager.h"
+
+#import "FIRLogger.h"
+#import "Private/FIRAuthAppCredential.h"
+#import "Private/FIRAuthAppCredentialManager.h"
+#import "FIRAuthGlobalWorkQueue.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @var kNotificationKey
+ @brief The key to locate payload data in the remote notification.
+ */
+static NSString *const kNotificationDataKey = @"com.google.firebase.auth";
+
+/** @var kNotificationReceiptKey
+ @brief The key for the receipt in the remote notification payload data.
+ */
+static NSString *const kNotificationReceiptKey = @"receipt";
+
+/** @var kNotificationSecretKey
+ @brief The key for the secret in the remote notification payload data.
+ */
+static NSString *const kNotificationSecretKey = @"secret";
+
+/** @var kNotificationProberKey
+ @brief The key for marking the prober in the remote notification payload data.
+ */
+static NSString *const kNotificationProberKey = @"warning";
+
+/** @var kProbingTimeout
+ @brief Timeout for probing whether the app delegate forwards the remote notification to us.
+ */
+static const NSTimeInterval kProbingTimeout = 1;
+
+@implementation FIRAuthNotificationManager {
+ /** @var _application
+ @brief The application.
+ */
+ UIApplication *_application;
+
+ /** @var _appCredentialManager
+ @brief The object to handle app credentials delivered via notification.
+ */
+ FIRAuthAppCredentialManager *_appCredentialManager;
+
+ /** @var _hasCheckedNotificationForwarding
+ @brief Whether notification forwarding has been checked or not.
+ */
+ BOOL _hasCheckedNotificationForwarding;
+
+ /** @var _isNotificationBeingForwarded
+ @brief Whether or not notification is being forwarded
+ */
+ BOOL _isNotificationBeingForwarded;
+
+ /** @var _pendingCallbacks
+ @brief All pending callbacks while a check is being performed.
+ */
+ NSMutableArray<FIRAuthNotificationForwardingCallback> *_pendingCallbacks;
+}
+
+- (instancetype)initWithApplication:(UIApplication *)application
+ appCredentialManager:(FIRAuthAppCredentialManager *)appCredentialManager {
+ self = [super init];
+ if (self) {
+ _application = application;
+ _appCredentialManager = appCredentialManager;
+ _timeout = kProbingTimeout;
+ }
+ return self;
+}
+
+- (void)checkNotificationForwardingWithCallback:(FIRAuthNotificationForwardingCallback)callback {
+ if (_pendingCallbacks) {
+ [_pendingCallbacks addObject:callback];
+ return;
+ }
+ if (_hasCheckedNotificationForwarding) {
+ callback(_isNotificationBeingForwarded);
+ return;
+ }
+ _hasCheckedNotificationForwarding = YES;
+ _pendingCallbacks =
+ [[NSMutableArray<FIRAuthNotificationForwardingCallback> alloc] initWithObjects:callback, nil];
+ dispatch_async(dispatch_get_main_queue(), ^{
+ NSDictionary *proberNotification = @{
+ kNotificationDataKey : @{
+ kNotificationProberKey : @"This fake notification should be forwarded to Firebase Auth."
+ }
+ };
+ if ([_application.delegate respondsToSelector:
+ @selector(application:didReceiveRemoteNotification:fetchCompletionHandler:)]) {
+ [_application.delegate application:_application
+ didReceiveRemoteNotification:proberNotification
+ fetchCompletionHandler:^(UIBackgroundFetchResult result) {}];
+ } else if ([_application.delegate respondsToSelector:
+ @selector(application:didReceiveRemoteNotification:)]) {
+ [_application.delegate application:_application
+ didReceiveRemoteNotification:proberNotification];
+ } else {
+ FIRLogError(kFIRLoggerAuth, @"I-AUT000015",
+ @"The UIApplicationDelegate must handle remote notifcation for phone number "
+ @"authentication to work.");
+ }
+ });
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_timeout * NSEC_PER_SEC)),
+ FIRAuthGlobalWorkQueue(), ^{
+ [self callBack];
+ });
+}
+
+- (BOOL)canHandleNotification:(NSDictionary *)notification {
+ NSDictionary *data = notification[kNotificationDataKey];
+ if ([data isKindOfClass:[NSString class]]) {
+ // Deserialize in case the data is a JSON string.
+ NSData *JSONData = [((NSString *)data) dataUsingEncoding:NSUTF8StringEncoding];
+ data = [NSJSONSerialization JSONObjectWithData:JSONData options:0 error:NULL];
+ }
+ if (![data isKindOfClass:[NSDictionary class]]) {
+ return NO;
+ }
+ if (data[kNotificationProberKey]) {
+ if (!_pendingCallbacks) {
+ // The prober notification probably comes from another instance, so pass it along.
+ return NO;
+ }
+ _isNotificationBeingForwarded = YES;
+ [self callBack];
+ return YES;
+ }
+ NSString *receipt = data[kNotificationReceiptKey];
+ if (![receipt isKindOfClass:[NSString class]]) {
+ return NO;
+ }
+ NSString *secret = data[kNotificationSecretKey];
+ if (![receipt isKindOfClass:[NSString class]]) {
+ return NO;
+ }
+ return [_appCredentialManager canFinishVerificationWithReceipt:receipt secret:secret];
+}
+
+#pragma mark - Internal methods
+
+/** @fn callBack
+ @brief Calls back all pending callbacks with the result of notification forwarding check.
+ */
+- (void)callBack {
+ if (!_pendingCallbacks) {
+ return;
+ }
+ NSArray<FIRAuthNotificationForwardingCallback> *allCallbacks = _pendingCallbacks;
+ _pendingCallbacks = nil;
+ for (FIRAuthNotificationForwardingCallback callback in allCallbacks) {
+ callback(_isNotificationBeingForwarded);
+ }
+};
+
+@end
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/FIRAuthProvider.m b/Firebase/Auth/Source/FIRAuthProvider.m
new file mode 100644
index 0000000..6df86d7
--- /dev/null
+++ b/Firebase/Auth/Source/FIRAuthProvider.m
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+// Declared 'extern' in FIRGoogleAuthProvider.h
+NSString *const FIRGoogleAuthProviderID = @"google.com";
+
+// Declared 'extern' in FIRFacebookAuthProvider.h
+NSString *const FIRFacebookAuthProviderID = @"facebook.com";
+
+// Declared 'extern' in FIREmailAuthProvider.h
+NSString *const FIREmailAuthProviderID = @"password";
+
+// Declared 'extern' in FIREmailAuthProvider.h
+NSString *const FIREmailPasswordAuthProviderID = @"password";
+
+// Declared 'extern' in FIRTwitterAuthProvider.h
+NSString *const FIRTwitterAuthProviderID = @"twitter.com";
+
+// Declared 'extern' in FIRGitHubAuthProvider.h
+NSString *const FIRGitHubAuthProviderID = @"github.com";
+
+// Declared 'extern' in FIRPhoneAuthProvider.h
+NSString *const FIRPhoneAuthProviderID = @"phone";
diff --git a/Firebase/Auth/Source/FIRAuthSerialTaskQueue.m b/Firebase/Auth/Source/FIRAuthSerialTaskQueue.m
new file mode 100644
index 0000000..47e6cd5
--- /dev/null
+++ b/Firebase/Auth/Source/FIRAuthSerialTaskQueue.m
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "Private/FIRAuthSerialTaskQueue.h"
+
+#import "Private/FIRAuthGlobalWorkQueue.h"
+
+@implementation FIRAuthSerialTaskQueue {
+ /** @var _dispatchQueue
+ @brief The asyncronous dispatch queue into which tasks are enqueued and processed
+ serially.
+ */
+ dispatch_queue_t _dispatchQueue;
+}
+
+- (instancetype)init {
+ self = [super init];
+ if (self) {
+ _dispatchQueue = dispatch_queue_create("com.google.firebase.auth.serialTaskQueue", NULL);
+ dispatch_set_target_queue(_dispatchQueue, FIRAuthGlobalWorkQueue());
+ }
+ return self;
+}
+
+- (void)enqueueTask:(FIRAuthSerialTask)task {
+ // This dispatch queue will run tasks serially in FIFO order, as long as it's not suspended.
+ dispatch_async(_dispatchQueue, ^{
+ // But as soon as a task is started, stop other tasks from running until the task calls it's
+ // completion handler, which allows the queue to resume processing of tasks. This allows the
+ // task to perform other asyncronous actions on other dispatch queues and "get back to us" when
+ // all of their sub-tasks are complete.
+ dispatch_suspend(_dispatchQueue);
+ task(^{
+ dispatch_resume(_dispatchQueue);
+ });
+ });
+}
+
+@end
diff --git a/Firebase/Auth/Source/FIRAuthSwiftNameSupport.h b/Firebase/Auth/Source/FIRAuthSwiftNameSupport.h
new file mode 100644
index 0000000..f58bdd7
--- /dev/null
+++ b/Firebase/Auth/Source/FIRAuthSwiftNameSupport.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FIR_SWIFT_NAME
+
+#import <Foundation/Foundation.h>
+
+// NS_SWIFT_NAME can only translate factory methods before the iOS 9.3 SDK.
+// // Wrap it in our own macro if it's a non-compatible SDK.
+#ifdef __IPHONE_9_3
+#define FIR_SWIFT_NAME(X) NS_SWIFT_NAME(X)
+#else
+#define FIR_SWIFT_NAME(X) // Intentionally blank.
+#endif // #ifdef __IPHONE_9_3
+
+#endif // FIR_SWIFT_NAME
diff --git a/Firebase/Auth/Source/FIRAuthUserDefaultsStorage.m b/Firebase/Auth/Source/FIRAuthUserDefaultsStorage.m
new file mode 100644
index 0000000..ad23f41
--- /dev/null
+++ b/Firebase/Auth/Source/FIRAuthUserDefaultsStorage.m
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "Private/FIRAuthUserDefaultsStorage.h"
+
+#if FIRAUTH_USER_DEFAULTS_STORAGE_AVAILABLE
+
+NS_ASSUME_NONNULL_BEGIN
+
+static NSString *const kPersistentDomainNamePrefix = @"com.google.Firebase.Auth.";
+
+@implementation FIRAuthUserDefaultsStorage {
+ /** @var _persistentDomainName
+ @brief The name of the persistent domain in user defaults.
+ */
+ NSString *_persistentDomainName;
+
+ /** @var _storage
+ @brief The backing NSUserDefaults storage for this instance.
+ */
+ NSUserDefaults *_storage;
+}
+
+- (id<FIRAuthStorage>)initWithService:(NSString *)service {
+ self = [super init];
+ if (self) {
+ _persistentDomainName = [kPersistentDomainNamePrefix stringByAppendingString:service];
+ _storage = [[NSUserDefaults alloc] init];
+ }
+ return self;
+}
+
+- (nullable NSData *)dataForKey:(NSString *)key error:(NSError **_Nullable)error {
+ if (error) {
+ *error = nil;
+ }
+ NSDictionary<NSString *, id> *allData = [_storage persistentDomainForName:_persistentDomainName];
+ return allData[key];
+}
+
+- (BOOL)setData:(NSData *)data forKey:(NSString *)key error:(NSError **_Nullable)error {
+ NSMutableDictionary<NSString *, id> *allData =
+ [([_storage persistentDomainForName:_persistentDomainName] ?: @{}) mutableCopy];
+ allData[key] = data;
+ [_storage setPersistentDomain:allData forName:_persistentDomainName];
+ return YES;
+}
+
+- (BOOL)removeDataForKey:(NSString *)key error:(NSError **_Nullable)error {
+ NSMutableDictionary<NSString *, id> *allData =
+ [[_storage persistentDomainForName:_persistentDomainName] mutableCopy];
+ [allData removeObjectForKey:key];
+ [_storage setPersistentDomain:allData forName:_persistentDomainName];
+ return YES;
+}
+
+- (void)clear {
+ [_storage setPersistentDomain:@{} forName:_persistentDomainName];
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+#endif // FIRAUTH_USER_DEFAULTS_STORAGE_AVAILABLE
diff --git a/Firebase/Auth/Source/FIRSecureTokenService.h b/Firebase/Auth/Source/FIRSecureTokenService.h
new file mode 100644
index 0000000..cb29127
--- /dev/null
+++ b/Firebase/Auth/Source/FIRSecureTokenService.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @typedef FIRFetchAccessTokenCallback
+ @brief The callback used to return the value of attempting to fetch an access token.
+
+ In the event the operation was successful @c token will be set and @c error will be @c nil.
+ In the event of failure @c token will be @c nil and @c error will be set.
+ @c tokenUpdated indicates whether either the access or the refresh token has been updated.
+
+ The token returned should be considered ephemeral and not cached. It should be used immediately
+ and discarded. All operations that need this token should call fetchAccessToken and do their
+ work from the callback.
+ */
+typedef void(^FIRFetchAccessTokenCallback)(NSString *_Nullable token,
+ NSError *_Nullable error,
+ BOOL tokenUpdated);
+
+/** @class FIRSecureTokenService
+ @brief Provides services for token exchanges and refreshes.
+ */
+@interface FIRSecureTokenService : NSObject <NSSecureCoding>
+
+/** @property rawAccessToken
+ @brief The cached access token.
+ @remarks This method is specifically for providing the access token to internal clients during
+ deserialization and sign-in events, and should not be used to retrieve the access token by
+ anyone else.
+ */
+@property(nonatomic, copy, readonly) NSString *rawAccessToken;
+
+/** @property refreshToken
+ @brief The refresh token for the user, or @c nil if the user has yet completed sign-in flow.
+ */
+@property(nonatomic, copy, readonly, nullable) NSString *refreshToken;
+
+/** @property accessTokenExpirationDate
+ @brief The expiration date of the cached access token.
+ */
+@property(nonatomic, copy, readonly, nullable) NSDate *accessTokenExpirationDate;
+
+/** @fn init
+ @brief Please use @c initWithAPIKey:authorizationCode: .
+ */
+- (instancetype)init NS_UNAVAILABLE;
+
+/** @fn initWithAPIKey:authorizationCode:
+ @brief Creates a @c FIRSecureTokenService with an authroization code.
+ @param APIKey A Google API key for making STS requests.
+ @param authorizationCode An authorization code which needs to be exchanged for STS tokens.
+ */
+- (nullable instancetype)initWithAPIKey:(NSString *)APIKey
+ authorizationCode:(NSString *)authorizationCode;
+
+/** @fn initWithAPIKey:authorizationCode:
+ @brief Creates a @c FIRSecureTokenService with an authroization code.
+ @param APIKey A Google API key for making STS requests.
+ @param accessToken The STS access token.
+ @param accessTokenExpirationDate The approximate expiration date of the access token.
+ @param refreshToken The STS refresh token.
+ */
+- (nullable instancetype)initWithAPIKey:(NSString *)APIKey
+ accessToken:(nullable NSString *)accessToken
+ accessTokenExpirationDate:(nullable NSDate *)accessTokenExpirationDate
+ refreshToken:(NSString *)refreshToken;
+
+/** @fn fetchAccessTokenForcingRefresh:callback:
+ @brief Fetch a fresh ephemeral access token for the ID associated with this instance. The token
+ received in the callback should be considered short lived and not cached.
+ @param forceRefresh Forces the token to be refreshed.
+ @param callback Callback block that will be called to return either the token or an error.
+ Invoked asyncronously on the auth global work queue in the future.
+ */
+- (void)fetchAccessTokenForcingRefresh:(BOOL)forceRefresh
+ callback:(FIRFetchAccessTokenCallback)callback;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/FIRSecureTokenService.m b/Firebase/Auth/Source/FIRSecureTokenService.m
new file mode 100644
index 0000000..e88b41c
--- /dev/null
+++ b/Firebase/Auth/Source/FIRSecureTokenService.m
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRSecureTokenService.h"
+
+#import "FIRAuth.h"
+#import "Private/FIRAuthKeychain.h"
+#import "Private/FIRAuthSerialTaskQueue.h"
+#import "FIRAuthBackend.h"
+#import "FIRSecureTokenRequest.h"
+#import "FIRSecureTokenResponse.h"
+
+/** @var kAPIKeyCodingKey
+ @brief The key used to encode the APIKey for NSSecureCoding.
+ */
+static NSString *const kAPIKeyCodingKey = @"APIKey";
+
+/** @var kRefreshTokenKey
+ @brief The key used to encode the refresh token for NSSecureCoding.
+ */
+static NSString *const kRefreshTokenKey = @"refreshToken";
+
+/** @var kAccessTokenKey
+ @brief The key used to encode the access token for NSSecureCoding.
+ */
+static NSString *const kAccessTokenKey = @"accessToken";
+
+/** @var kAccessTokenExpirationDateKey
+ @brief The key used to encode the access token expiration date for NSSecureCoding.
+ */
+static NSString *const kAccessTokenExpirationDateKey = @"accessTokenExpirationDate";
+
+/** @var kFiveMinutes
+ @brief Five minutes (in seconds.)
+ */
+static const NSTimeInterval kFiveMinutes = 5 * 60;
+
+@interface FIRSecureTokenService ()
+/** @fn initWithAPIKey:
+ @brief Creates a @c FIRSecureTokenService without a credential.
+ @param APIKey A Google API key for making STS requests.
+ */
+- (nullable instancetype)initWithAPIKey:(NSString *)APIKey NS_DESIGNATED_INITIALIZER;
+@end
+
+@implementation FIRSecureTokenService {
+ /** @var _APIKey
+ @brief A Google API key for making Secure Token Service requests.
+ */
+ NSString *_APIKey;
+
+ /** @var _taskQueue
+ @brief Used to serialize all requests for access tokens.
+ */
+ FIRAuthSerialTaskQueue *_taskQueue;
+
+ /** @var _authorizationCode
+ @brief An authorization code which needs to be exchanged for Secure Token Service tokens.
+ */
+ NSString *_Nullable _authorizationCode;
+
+ /** @var _accessToken
+ @brief The currently cached access token. Or |nil| if no token is currently cached.
+ */
+ NSString *_Nullable _accessToken;
+}
+
+- (instancetype)init {
+ [self doesNotRecognizeSelector:_cmd];
+ return nil;
+}
+
+- (nullable instancetype)initWithAPIKey:(NSString *)APIKey {
+ self = [super init];
+ if (self) {
+ _APIKey = [APIKey copy];
+ _taskQueue = [[FIRAuthSerialTaskQueue alloc] init];
+ }
+ return self;
+}
+
+- (nullable instancetype)initWithAPIKey:(NSString *)APIKey
+ authorizationCode:(NSString *)authorizationCode {
+ self = [self initWithAPIKey:APIKey];
+ if (self) {
+ _authorizationCode = [authorizationCode copy];
+ }
+ return self;
+}
+
+- (nullable instancetype)initWithAPIKey:(NSString *)APIKey
+ accessToken:(nullable NSString *)accessToken
+ accessTokenExpirationDate:(nullable NSDate *)accessTokenExpirationDate
+ refreshToken:(NSString *)refreshToken {
+ self = [self initWithAPIKey:APIKey];
+ if (self) {
+ _accessToken = [accessToken copy];
+ _accessTokenExpirationDate = [accessTokenExpirationDate copy];
+ _refreshToken = [refreshToken copy];
+ }
+ return self;
+}
+
+- (void)fetchAccessTokenForcingRefresh:(BOOL)forceRefresh
+ callback:(FIRFetchAccessTokenCallback)callback {
+ [_taskQueue enqueueTask:^(FIRAuthSerialTaskCompletionBlock complete) {
+ if (!forceRefresh && [self hasValidAccessToken]) {
+ complete();
+ callback(_accessToken, nil, NO);
+ } else {
+ [self requestAccessToken:^(NSString *_Nullable token,
+ NSError *_Nullable error,
+ BOOL tokenUpdated) {
+ complete();
+ callback(token, error, tokenUpdated);
+ }];
+ }
+ }];
+}
+
+- (NSString *)rawAccessToken {
+ return _accessToken;
+}
+
+#pragma mark - NSSecureCoding
+
++ (BOOL)supportsSecureCoding {
+ return YES;
+}
+
+- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder {
+ NSString *APIKey = [aDecoder decodeObjectOfClass:[NSString class] forKey:kAPIKeyCodingKey];
+ NSString *refreshToken = [aDecoder decodeObjectOfClass:[NSString class] forKey:kRefreshTokenKey];
+ NSString *accessToken = [aDecoder decodeObjectOfClass:[NSString class] forKey:kAccessTokenKey];
+ NSDate *accessTokenExpirationDate =
+ [aDecoder decodeObjectOfClass:[NSDate class] forKey:kAccessTokenExpirationDateKey];
+ if (!APIKey || !refreshToken) {
+ return nil;
+ }
+ self = [self initWithAPIKey:APIKey];
+ if (self) {
+ _refreshToken = refreshToken;
+ _accessToken = accessToken;
+ _accessTokenExpirationDate = accessTokenExpirationDate;
+ }
+ return self;
+}
+
+- (void)encodeWithCoder:(NSCoder *)aCoder {
+ [aCoder encodeObject:_APIKey forKey:kAPIKeyCodingKey];
+ // Authorization code is not encoded because it is not long-lived.
+ [aCoder encodeObject:_refreshToken forKey:kRefreshTokenKey];
+ [aCoder encodeObject:_accessToken forKey:kAccessTokenKey];
+ [aCoder encodeObject:_accessTokenExpirationDate forKey:kAccessTokenExpirationDateKey];
+}
+
+#pragma mark - Private methods
+
+/** @fn requestAccessToken:
+ @brief Makes a request to STS for an access token.
+ @details This handles both the case that the token has not been granted yet and that it just
+ needs to be refreshed. The caller is responsible for making sure that this is occurring in
+ a @c _taskQueue task.
+ @param callback Called when the fetch is complete. Invoked asynchronously on the main thread in
+ the future.
+ @remarks Because this method is guaranteed to only be called from tasks enqueued in
+ @c _taskQueue, we do not need any @synchronized guards around access to _accessToken/etc.
+ since only one of those tasks is ever running at a time, and those tasks are the only
+ access to and mutation of these instance variables.
+ */
+- (void)requestAccessToken:(FIRFetchAccessTokenCallback)callback {
+ FIRSecureTokenRequest *request;
+ if (_refreshToken.length) {
+ request = [FIRSecureTokenRequest refreshRequestWithRefreshToken:_refreshToken APIKey:_APIKey];
+ } else {
+ request = [FIRSecureTokenRequest authCodeRequestWithCode:_authorizationCode APIKey:_APIKey];
+ }
+ [FIRAuthBackend secureToken:request
+ callback:^(FIRSecureTokenResponse *_Nullable response,
+ NSError *_Nullable error) {
+ BOOL tokenUpdated = NO;
+ NSString *newAccessToken = response.accessToken;
+ if (newAccessToken.length && ![newAccessToken isEqualToString:_accessToken]) {
+ _accessToken = [newAccessToken copy];
+ _accessTokenExpirationDate = response.approximateExpirationDate;
+ tokenUpdated = YES;
+ }
+ NSString *newRefreshToken = response.refreshToken;
+ if (newRefreshToken.length && ![newRefreshToken isEqualToString:_refreshToken]) {
+ _refreshToken = [newRefreshToken copy];
+ tokenUpdated = YES;
+ }
+ callback(newAccessToken, error, tokenUpdated);
+ }];
+}
+
+- (BOOL)hasValidAccessToken {
+ return _accessToken && [_accessTokenExpirationDate timeIntervalSinceNow] > kFiveMinutes;
+}
+
+@end
diff --git a/Firebase/Auth/Source/FIRUser.h b/Firebase/Auth/Source/FIRUser.h
new file mode 100644
index 0000000..ebe8b81
--- /dev/null
+++ b/Firebase/Auth/Source/FIRUser.h
@@ -0,0 +1,463 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "FIRAuth.h"
+#import "FIRAuthDataResult.h"
+#import "FIRAuthSwiftNameSupport.h"
+#import "FIRUserInfo.h"
+
+@class FIRPhoneAuthCredential;
+@class FIRUserProfileChangeRequest;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @typedef FIRAuthTokenCallback
+ @brief The type of block called when a token is ready for use.
+ @see FIRUser.getIDTokenWithCompletion:
+ @see FIRUser.getIDTokenForcingRefresh:withCompletion:
+
+ @param token Optionally; an access token if the request was successful.
+ @param error Optionally; the error which occurred - or nil if the request was successful.
+
+ @remarks One of: @c token or @c error will always be non-nil.
+ */
+typedef void (^FIRAuthTokenCallback)(NSString *_Nullable token, NSError *_Nullable error)
+ FIR_SWIFT_NAME(AuthTokenCallback);
+
+/** @typedef FIRUserProfileChangeCallback
+ @brief The type of block called when a user profile change has finished.
+
+ @param error Optionally; the error which occurred - or nil if the request was successful.
+ */
+typedef void (^FIRUserProfileChangeCallback)(NSError *_Nullable error)
+ FIR_SWIFT_NAME(UserProfileChangeCallback);
+
+/** @typedef FIRSendEmailVerificationCallback
+ @brief The type of block called when a request to send an email verification has finished.
+
+ @param error Optionally; the error which occurred - or nil if the request was successful.
+ */
+typedef void (^FIRSendEmailVerificationCallback)(NSError *_Nullable error)
+ FIR_SWIFT_NAME(SendEmailVerificationCallback);
+
+/** @class FIRUser
+ @brief Represents a user.
+ @remarks This class is thread-safe.
+ */
+FIR_SWIFT_NAME(User)
+@interface FIRUser : NSObject <FIRUserInfo>
+
+/** @property anonymous
+ @brief Indicates the user represents an anonymous user.
+ */
+@property(nonatomic, readonly, getter=isAnonymous) BOOL anonymous;
+
+/** @property emailVerified
+ @brief Indicates the email address associated with this user has been verified.
+ */
+@property(nonatomic, readonly, getter=isEmailVerified) BOOL emailVerified;
+
+/** @property refreshToken
+ @brief A refresh token; useful for obtaining new access tokens independently.
+ @remarks This property should only be used for advanced scenarios, and is not typically needed.
+ */
+@property(nonatomic, readonly, nullable) NSString *refreshToken;
+
+/** @property providerData
+ @brief Profile data for each identity provider, if any.
+ @remarks This data is cached on sign-in and updated when linking or unlinking.
+ */
+@property(nonatomic, readonly, nonnull) NSArray<id<FIRUserInfo>> *providerData;
+
+/** @fn init
+ @brief This class should not be instantiated.
+ @remarks To retrieve the current user, use @c FIRAuth.currentUser. To sign a user
+ in or out, use the methods on @c FIRAuth.
+ */
+- (instancetype)init NS_UNAVAILABLE;
+
+/** @fn updateEmail:completion:
+ @brief Updates the email address for the user. On success, the cached user profile data is
+ updated.
+ @remarks May fail if there is already an account with this email address that was created using
+ email and password authentication.
+
+ @param email The email address for the user.
+ @param completion Optionally; the block invoked when the user profile change has finished.
+ Invoked asynchronously on the main thread in the future.
+
+ @remarks Possible error codes:
+ <ul>
+ <li>@c FIRAuthErrorCodeInvalidRecipientEmail - Indicates an invalid recipient email was
+ sent in the request.
+ </li>
+ <li>@c FIRAuthErrorCodeInvalidSender - Indicates an invalid sender email is set in
+ the console for this action.
+ </li>
+ <li>@c FIRAuthErrorCodeInvalidMessagePayload - Indicates an invalid email template for
+ sending update email.
+ </li>
+ <li>@c FIRAuthErrorCodeEmailAlreadyInUse - Indicates the email is already in use by another
+ account.
+ </li>
+ <li>@c FIRAuthErrorCodeInvalidEmail - Indicates the email address is malformed.
+ </li>
+ <li>@c FIRAuthErrorCodeRequiresRecentLogin - Updating a user’s email is a security
+ sensitive operation that requires a recent login from the user. This error indicates
+ the user has not signed in recently enough. To resolve, reauthenticate the user by
+ invoking reauthenticateWithCredential:completion: on FIRUser.
+ </li>
+ </ul>
+
+ @remarks See @c FIRAuthErrors for a list of error codes that are common to all FIRUser methods.
+ */
+- (void)updateEmail:(NSString *)email completion:(nullable FIRUserProfileChangeCallback)completion
+ FIR_SWIFT_NAME(updateEmail(to:completion:));
+
+/** @fn updatePassword:completion:
+ @brief Updates the password for the user. On success, the cached user profile data is updated.
+
+ @param password The new password for the user.
+ @param completion Optionally; the block invoked when the user profile change has finished.
+ Invoked asynchronously on the main thread in the future.
+
+ @remarks Possible error codes:
+ <ul>
+ <li>@c FIRAuthErrorCodeOperationNotAllowed - Indicates the administrator disabled
+ sign in with the specified identity provider.
+ </li>
+ <li>@c FIRAuthErrorCodeRequiresRecentLogin - Updating a user’s password is a security
+ sensitive operation that requires a recent login from the user. This error indicates
+ the user has not signed in recently enough. To resolve, reauthenticate the user by
+ invoking reauthenticateWithCredential:completion: on FIRUser.
+ </li>
+ <li>@c FIRAuthErrorCodeWeakPassword - Indicates an attempt to set a password that is
+ considered too weak. The NSLocalizedFailureReasonErrorKey field in the NSError.userInfo
+ dictionary object will contain more detailed explanation that can be shown to the user.
+ </li>
+ </ul>
+
+ @remarks See @c FIRAuthErrors for a list of error codes that are common to all FIRUser methods.
+ */
+- (void)updatePassword:(NSString *)password
+ completion:(nullable FIRUserProfileChangeCallback)completion
+ FIR_SWIFT_NAME(updatePassword(to:completion:));
+
+/** @fn updatePhoneNumberCredential:completion:
+ @brief Updates the phone number for the user. On success, the cached user profile data is
+ updated.
+
+ @param phoneNumberCredential The new phone number credential corresponding to the phone number
+ to be added to the firebaes account, if a phone number is already linked to the account this
+ new phone number will replace it.
+ @param completion Optionally; the block invoked when the user profile change has finished.
+ Invoked asynchronously on the main thread in the future.
+
+ @remarks Possible error codes:
+ <ul>
+ <li>@c FIRAuthErrorCodeRequiresRecentLogin - Updating a user’s phone number is a security
+ sensitive operation that requires a recent login from the user. This error indicates
+ the user has not signed in recently enough. To resolve, reauthenticate the user by
+ invoking reauthenticateWithCredential:completion: on FIRUser.
+ </li>
+ </ul>
+
+ @remarks See @c FIRAuthErrors for a list of error codes that are common to all FIRUser methods.
+ */
+- (void)updatePhoneNumberCredential:(FIRPhoneAuthCredential *)phoneNumberCredential
+ completion:(nullable FIRUserProfileChangeCallback)completion;
+
+/** @fn profileChangeRequest
+ @brief Creates an object which may be used to change the user's profile data.
+
+ @remarks Set the properties of the returned object, then call
+ @c FIRUserProfileChangeRequest.commitChangesWithCallback: to perform the updates atomically.
+
+ @return An object which may be used to change the user's profile data atomically.
+ */
+- (FIRUserProfileChangeRequest *)profileChangeRequest FIR_SWIFT_NAME(createProfileChangeRequest());
+
+/** @fn reloadWithCompletion:
+ @brief Reloads the user's profile data from the server.
+
+ @param completion Optionally; the block invoked when the reload has finished. Invoked
+ asynchronously on the main thread in the future.
+
+ @remarks May fail with a @c FIRAuthErrorCodeRequiresRecentLogin error code. In this case
+ you should call @c FIRUser.reauthenticateWithCredential:completion: before re-invoking
+ @c FIRUser.updateEmail:completion:.
+
+ @remarks See @c FIRAuthErrors for a list of error codes that are common to all API methods.
+ */
+- (void)reloadWithCompletion:(nullable FIRUserProfileChangeCallback)completion;
+
+/** @fn reauthenticateWithCredential:completion:
+ @brief Convenience method for @c reauthenticateAndRetrieveDataWithCredential:completion: This
+ method doesn't return additional identity provider data.
+ */
+- (void)reauthenticateWithCredential:(FIRAuthCredential *)credential
+ completion:(nullable FIRUserProfileChangeCallback)completion;
+
+/** @fn reauthenticateWithCredential:completion:
+ @brief Renews the user's authentication tokens by validating a fresh set of credentials supplied
+ by the user and returns additional identity provider data.
+
+ @param credential A user-supplied credential, which will be validated by the server. This can be
+ a successful third-party identity provider sign-in, or an email address and password.
+ @param completion Optionally; the block invoked when the re-authentication operation has
+ finished. Invoked asynchronously on the main thread in the future.
+
+ @remarks If the user associated with the supplied credential is different from the current user,
+ or if the validation of the supplied credentials fails; an error is returned and the current
+ user remains signed in.
+
+ @remarks Possible error codes:
+ <ul>
+ <li>@c FIRAuthErrorCodeInvalidCredential - Indicates the supplied credential is invalid.
+ This could happen if it has expired or it is malformed.
+ </li>
+ <li>@c FIRAuthErrorCodeOperationNotAllowed - Indicates that accounts with the
+ identity provider represented by the credential are not enabled. Enable them in the
+ Auth section of the Firebase console.
+ </li>
+ <li>@c FIRAuthErrorCodeEmailAlreadyInUse - Indicates the email asserted by the credential
+ (e.g. the email in a Facebook access token) is already in use by an existing account,
+ that cannot be authenticated with this method. Call fetchProvidersForEmail for
+ this user’s email and then prompt them to sign in with any of the sign-in providers
+ returned. This error will only be thrown if the "One account per email address"
+ setting is enabled in the Firebase console, under Auth settings. Please note that the
+ error code raised in this specific situation may not be the same on Web and Android.
+ </li>
+ <li>@c FIRAuthErrorCodeUserDisabled - Indicates the user's account is disabled.
+ </li>
+ <li>@c FIRAuthErrorCodeWrongPassword - Indicates the user attempted reauthentication with
+ an incorrect password, if credential is of the type EmailPasswordAuthCredential.
+ </li>
+ <li>@c FIRAuthErrorCodeUserMismatch - Indicates that an attempt was made to
+ reauthenticate with a user which is not the current user.
+ </li>
+ <li>@c FIRAuthErrorCodeInvalidEmail - Indicates the email address is malformed.</li>
+ </ul>
+ @remarks See @c FIRAuthErrors for a list of error codes that are common to all API methods.
+ */
+- (void)reauthenticateAndRetrieveDataWithCredential:(FIRAuthCredential *) credential
+ completion:(nullable FIRAuthDataResultCallback) completion;
+
+/** @fn getIDTokenWithCompletion:
+ @brief Retrieves the Firebase authentication token, possibly refreshing it if it has expired.
+
+ @param completion Optionally; the block invoked when the token is available. Invoked
+ asynchronously on the main thread in the future.
+
+ @remarks See @c FIRAuthErrors for a list of error codes that are common to all API methods.
+ */
+- (void)getIDTokenWithCompletion:(nullable FIRAuthTokenCallback)completion
+ FIR_SWIFT_NAME(getIDToken(completion:));
+
+/** @fn getTokenWithCompletion:
+ @brief Please use @c getIDTokenWithCompletion: instead.
+
+ @param completion Optionally; the block invoked when the token is available. Invoked
+ asynchronously on the main thread in the future.
+
+ @remarks See @c FIRAuthErrors for a list of error codes that are common to all API methods.
+ */
+- (void)getTokenWithCompletion:(nullable FIRAuthTokenCallback)completion
+ FIR_SWIFT_NAME(getToken(completion:)) __attribute__((deprecated));
+
+/** @fn getIDTokenForcingRefresh:completion:
+ @brief Retrieves the Firebase authentication token, possibly refreshing it if it has expired.
+
+ @param forceRefresh Forces a token refresh. Useful if the token becomes invalid for some reason
+ other than an expiration.
+ @param completion Optionally; the block invoked when the token is available. Invoked
+ asynchronously on the main thread in the future.
+
+ @remarks The authentication token will be refreshed (by making a network request) if it has
+ expired, or if @c forceRefresh is YES.
+
+ @remarks See @c FIRAuthErrors for a list of error codes that are common to all API methods.
+ */
+- (void)getIDTokenForcingRefresh:(BOOL)forceRefresh
+ completion:(nullable FIRAuthTokenCallback)completion;
+
+/** @fn getTokenForcingRefresh:completion:
+ @brief Please use getIDTokenForcingRefresh:completion instead.
+
+ @param forceRefresh Forces a token refresh. Useful if the token becomes invalid for some reason
+ other than an expiration.
+ @param completion Optionally; the block invoked when the token is available. Invoked
+ asynchronously on the main thread in the future.
+
+ @remarks The authentication token will be refreshed (by making a network request) if it has
+ expired, or if @c forceRefresh is YES.
+
+ @remarks See @c FIRAuthErrors for a list of error codes that are common to all API methods.
+ */
+- (void)getTokenForcingRefresh:(BOOL)forceRefresh
+ completion:(nullable FIRAuthTokenCallback)completion
+ __attribute__((deprecated));
+
+/** @fn linkWithCredential:completion:
+ @brief Convenience method for @c linkAndRetrieveDataWithCredential:completion: This method
+ doesn't return additional identity provider data.
+ */
+- (void)linkWithCredential:(FIRAuthCredential *)credential
+ completion:(nullable FIRAuthResultCallback)completion;
+
+/** @fn linkAndRetrieveDataWithCredential:completion:
+ @brief Associates a user account from a third-party identity provider with this user and
+ returns additional identity provider data.
+
+ @param credential The credential for the identity provider.
+ @param completion Optionally; the block invoked when the unlinking is complete, or fails.
+ Invoked asynchronously on the main thread in the future.
+
+ @remarks Possible error codes:
+ <ul>
+ <li>@c FIRAuthErrorCodeProviderAlreadyLinked - Indicates an attempt to link a provider of a
+ type already linked to this account.
+ </li>
+ <li>@c FIRAuthErrorCodeCredentialAlreadyInUse - Indicates an attempt to link with a
+ credential
+ that has already been linked with a different Firebase account.
+ </li>
+ <li>@c FIRAuthErrorCodeOperationNotAllowed - Indicates that accounts with the identity
+ provider represented by the credential are not enabled. Enable them in the Auth section
+ of the Firebase console.
+ </li>
+ </ul>
+
+ @remarks This method may also return error codes associated with updateEmail:completion: and
+ updatePassword:completion: on FIRUser.
+
+ @remarks See @c FIRAuthErrors for a list of error codes that are common to all FIRUser methods.
+ */
+- (void)linkAndRetrieveDataWithCredential:(FIRAuthCredential *) credential
+ completion:(nullable FIRAuthDataResultCallback) completion;
+
+/** @fn unlinkFromProvider:completion:
+ @brief Disassociates a user account from a third-party identity provider with this user.
+
+ @param provider The provider ID of the provider to unlink.
+ @param completion Optionally; the block invoked when the unlinking is complete, or fails.
+ Invoked asynchronously on the main thread in the future.
+
+ @remarks Possible error codes:
+ <ul>
+ <li>@c FIRAuthErrorCodeNoSuchProvider - Indicates an attempt to unlink a provider
+ that is not linked to the account.
+ </li>
+ <li>@c FIRAuthErrorCodeRequiresRecentLogin - Updating email is a security sensitive
+ operation that requires a recent login from the user. This error indicates the user
+ has not signed in recently enough. To resolve, reauthenticate the user by invoking
+ reauthenticateWithCredential:completion: on FIRUser.
+ </li>
+ </ul>
+
+ @remarks See @c FIRAuthErrors for a list of error codes that are common to all FIRUser methods.
+ */
+- (void)unlinkFromProvider:(NSString *)provider
+ completion:(nullable FIRAuthResultCallback)completion;
+
+/** @fn sendEmailVerificationWithCompletion:
+ @brief Initiates email verification for the user.
+
+ @param completion Optionally; the block invoked when the request to send an email verification
+ is complete, or fails. Invoked asynchronously on the main thread in the future.
+
+ @remarks Possible error codes:
+ <ul>
+ <li>@c FIRAuthErrorCodeInvalidRecipientEmail - Indicates an invalid recipient email was
+ sent in the request.
+ </li>
+ <li>@c FIRAuthErrorCodeInvalidSender - Indicates an invalid sender email is set in
+ the console for this action.
+ </li>
+ <li>@c FIRAuthErrorCodeInvalidMessagePayload - Indicates an invalid email template for
+ sending update email.
+ </li>
+ <li>@c FIRAuthErrorCodeUserNotFound - Indicates the user account was not found.</li>
+ </ul>
+
+ @remarks See @c FIRAuthErrors for a list of error codes that are common to all FIRUser methods.
+ */
+- (void)sendEmailVerificationWithCompletion:(nullable FIRSendEmailVerificationCallback)completion;
+
+/** @fn deleteWithCompletion:
+ @brief Deletes the user account (also signs out the user, if this was the current user).
+
+ @param completion Optionally; the block invoked when the request to delete the account is
+ complete, or fails. Invoked asynchronously on the main thread in the future.
+
+ @remarks Possible error codes:
+ <ul>
+ <li>@c FIRAuthErrorCodeRequiresRecentLogin - Updating email is a security sensitive
+ operation that requires a recent login from the user. This error indicates the user
+ has not signed in recently enough. To resolve, reauthenticate the user by invoking
+ reauthenticateWithCredential:completion: on FIRUser.
+ </li>
+ </ul>
+
+ @remarks See @c FIRAuthErrors for a list of error codes that are common to all FIRUser methods.
+
+ */
+- (void)deleteWithCompletion:(nullable FIRUserProfileChangeCallback)completion;
+
+@end
+
+/** @class FIRUserProfileChangeRequest
+ @brief Represents an object capable of updating a user's profile data.
+ @remarks Properties are marked as being part of a profile update when they are set. Setting a
+ property value to nil is not the same as leaving the property unassigned.
+ */
+FIR_SWIFT_NAME(UserProfileChangeRequest)
+@interface FIRUserProfileChangeRequest : NSObject
+
+/** @fn init
+ @brief Please use @c FIRUser.profileChangeRequest
+ */
+- (instancetype)init NS_UNAVAILABLE;
+
+/** @property displayName
+ @brief The user's display name.
+ @remarks It is an error to set this property after calling
+ @c FIRUserProfileChangeRequest.commitChangesWithCallback:
+ */
+@property(nonatomic, copy, nullable) NSString *displayName;
+
+/** @property photoURL
+ @brief The user's photo URL.
+ @remarks It is an error to set this property after calling
+ @c FIRUserProfileChangeRequest.commitChangesWithCallback:
+ */
+@property(nonatomic, copy, nullable) NSURL *photoURL;
+
+/** @fn commitChangesWithCompletion:
+ @brief Commits any pending changes.
+ @remarks This method should only be called once. Once called, property values should not be
+ changed.
+
+ @param completion Optionally; the block invoked when the user profile change has been applied.
+ Invoked asynchronously on the main thread in the future.
+ */
+- (void)commitChangesWithCompletion:(nullable FIRUserProfileChangeCallback)completion;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/FIRUser.m b/Firebase/Auth/Source/FIRUser.m
new file mode 100644
index 0000000..f0c3226
--- /dev/null
+++ b/Firebase/Auth/Source/FIRUser.m
@@ -0,0 +1,1170 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "Private/FIRUser_Internal.h"
+
+#import "AuthProviders/EmailPassword/FIREmailPasswordAuthCredential.h"
+#import "AuthProviders/EmailPassword/FIREmailAuthProvider.h"
+#import "AuthProviders/Phone/FIRPhoneAuthCredential_Internal.h"
+#import "AuthProviders/Phone/FIRPhoneAuthProvider.h"
+#import "Private/FIRAdditionalUserInfo_Internal.h"
+#import "FIRAuth.h"
+#import "Private/FIRAuthCredential_Internal.h"
+#import "Private/FIRAuthDataResult_Internal.h"
+#import "Private/FIRAuthErrorUtils.h"
+#import "Private/FIRAuthGlobalWorkQueue.h"
+#import "Private/FIRAuthSerialTaskQueue.h"
+#import "Private/FIRAuth_Internal.h"
+#import "FIRSecureTokenService.h"
+#import "FIRUserInfoImpl.h"
+#import "FIRAuthBackend.h"
+#import "FIRDeleteAccountRequest.h"
+#import "FIRDeleteAccountResponse.h"
+#import "FIRGetAccountInfoRequest.h"
+#import "FIRGetAccountInfoResponse.h"
+#import "FIRGetOOBConfirmationCodeRequest.h"
+#import "FIRGetOOBConfirmationCodeResponse.h"
+#import "FIRSetAccountInfoRequest.h"
+#import "FIRSetAccountInfoResponse.h"
+#import "FIRVerifyAssertionRequest.h"
+#import "FIRVerifyAssertionResponse.h"
+#import "FIRVerifyCustomTokenRequest.h"
+#import "FIRVerifyCustomTokenResponse.h"
+#import "FIRVerifyPasswordRequest.h"
+#import "FIRVerifyPasswordResponse.h"
+#import "FIRVerifyPhoneNumberRequest.h"
+#import "FIRVerifyPhoneNumberResponse.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @var kUserIDCodingKey
+ @brief The key used to encode the user ID for NSSecureCoding.
+ */
+static NSString *const kUserIDCodingKey = @"userID";
+
+/** @var kHasEmailPasswordCredentialCodingKey
+ @brief The key used to encode the hasEmailPasswordCredential property for NSSecureCoding.
+ */
+static NSString *const kHasEmailPasswordCredentialCodingKey = @"hasEmailPassword";
+
+/** @var kAnonymousCodingKey
+ @brief The key used to encode the anonymous property for NSSecureCoding.
+ */
+static NSString *const kAnonymousCodingKey = @"anonymous";
+
+/** @var kEmailCodingKey
+ @brief The key used to encode the email property for NSSecureCoding.
+ */
+static NSString *const kEmailCodingKey = @"email";
+
+/** @var kEmailVerifiedCodingKey
+ @brief The key used to encode the isEmailVerified property for NSSecureCoding.
+ */
+static NSString *const kEmailVerifiedCodingKey = @"emailVerified";
+
+/** @var kDisplayNameCodingKey
+ @brief The key used to encode the displayName property for NSSecureCoding.
+ */
+static NSString *const kDisplayNameCodingKey = @"displayName";
+
+/** @var kPhotoURLCodingKey
+ @brief The key used to encode the photoURL property for NSSecureCoding.
+ */
+static NSString *const kPhotoURLCodingKey = @"photoURL";
+
+/** @var kProviderDataKey
+ @brief The key used to encode the providerData instance variable for NSSecureCoding.
+ */
+static NSString *const kProviderDataKey = @"providerData";
+
+/** @var kAPIKeyCodingKey
+ @brief The key used to encode the APIKey instance variable for NSSecureCoding.
+ */
+static NSString *const kAPIKeyCodingKey = @"APIKey";
+
+/** @var kTokenServiceCodingKey
+ @brief The key used to encode the tokenService instance variable for NSSecureCoding.
+ */
+static NSString *const kTokenServiceCodingKey = @"tokenService";
+
+/** @var kMissingUsersErrorMessage
+ @brief The error message when there is no users array in the getAccountInfo response.
+ */
+static NSString *const kMissingUsersErrorMessage = @"users";
+
+/** @typedef CallbackWithError
+ @brief The type for a callback block that only takes an error parameter.
+ */
+typedef void (^CallbackWithError)(NSError *_Nullable);
+
+/** @typedef CallbackWithUserAndError
+ @brief The type for a callback block that takes a user parameter and an error parameter.
+ */
+typedef void (^CallbackWithUserAndError)(FIRUser *_Nullable, NSError *_Nullable);
+
+/** @typedef CallbackWithUserAndError
+ @brief The type for a callback block that takes a user parameter and an error parameter.
+ */
+typedef void (^CallbackWithAuthDataResultAndError)(FIRAuthDataResult *_Nullable,
+ NSError *_Nullable);
+
+/** @var kMissingPasswordReason
+ @brief The reason why the @c FIRAuthErrorCodeWeakPassword error is thrown.
+ @remarks This error message will be localized in the future.
+ */
+static NSString *const kMissingPasswordReason = @"Missing Password";
+
+/** @fn callInMainThreadWithError
+ @brief Calls a callback in main thread with error.
+ @param callback The callback to be called in main thread.
+ @param error The error to pass to callback.
+ */
+static void callInMainThreadWithError(_Nullable CallbackWithError callback,
+ NSError *_Nullable error) {
+ if (callback) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ callback(error);
+ });
+ }
+}
+
+/** @fn callInMainThreadWithUserAndError
+ @brief Calls a callback in main thread with user and error.
+ @param callback The callback to be called in main thread.
+ @param user The user to pass to callback if there is no error.
+ @param error The error to pass to callback.
+ */
+static void callInMainThreadWithUserAndError(_Nullable CallbackWithUserAndError callback,
+ FIRUser *_Nonnull user,
+ NSError *_Nullable error) {
+ if (callback) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ callback(error ? nil : user, error);
+ });
+ }
+}
+
+/** @fn callInMainThreadWithUserAndError
+ @brief Calls a callback in main thread with user and error.
+ @param callback The callback to be called in main thread.
+ @param result The result to pass to callback if there is no error.
+ @param error The error to pass to callback.
+ */
+static void callInMainThreadWithAuthDataResultAndError(
+ _Nullable CallbackWithAuthDataResultAndError callback,
+ FIRAuthDataResult *_Nullable result,
+ NSError *_Nullable error) {
+ if (callback) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ callback(result, error);
+ });
+ }
+}
+
+@interface FIRUserProfileChangeRequest ()
+
+/** @fn initWithUser:
+ @brief Designated initializer.
+ @param user The user for which we are updating profile information.
+ */
+- (nullable instancetype)initWithUser:(FIRUser *)user NS_DESIGNATED_INITIALIZER;
+
+@end
+
+@interface FIRUser ()
+
+/** @fn initWithAPIKey:
+ @brief Designated initializer
+ @param APIKey The client API key for making RPCs.
+ */
+- (nullable instancetype)initWithAPIKey:(NSString *)APIKey NS_DESIGNATED_INITIALIZER;
+
+@end
+
+@implementation FIRUser {
+ /** @var _hasEmailPasswordCredential
+ @brief Whether or not the user can be authenticated by using Firebase email and password.
+ */
+ BOOL _hasEmailPasswordCredential;
+
+ /** @var _providerData
+ @brief Provider specific user data.
+ */
+ NSDictionary<NSString *, FIRUserInfoImpl *> *_providerData;
+
+ /** @var _APIKey
+ @brief The application's API Key.
+ */
+ NSString *_APIKey;
+
+ /** @var _taskQueue
+ @brief Used to serialize the update profile calls.
+ */
+ FIRAuthSerialTaskQueue *_taskQueue;
+
+ /** @var _tokenService
+ @brief A secure token service associated with this user. For performing token exchanges and
+ refreshing access tokens.
+ */
+ FIRSecureTokenService *_tokenService;
+}
+
+#pragma mark - Properties
+
+// Explicitly @synthesize because these properties are defined in FIRUserInfo protocol.
+@synthesize uid = _userID;
+@synthesize displayName = _displayName;
+@synthesize photoURL = _photoURL;
+@synthesize email = _email;
+@synthesize phoneNumber = _phoneNumber;
+
+#pragma mark -
+
++ (void)retrieveUserWithAPIKey:(NSString *)APIKey
+ accessToken:(NSString *)accessToken
+ accessTokenExpirationDate:(NSDate *)accessTokenExpirationDate
+ refreshToken:(NSString *)refreshToken
+ anonymous:(BOOL)anonymous
+ callback:(FIRRetrieveUserCallback)callback {
+ FIRSecureTokenService *tokenService =
+ [[FIRSecureTokenService alloc] initWithAPIKey:APIKey
+ accessToken:accessToken
+ accessTokenExpirationDate:accessTokenExpirationDate
+ refreshToken:refreshToken];
+ FIRUser *user = [[self alloc] initWithAPIKey:APIKey
+ tokenService:tokenService];
+ [user internalGetTokenWithCallback:^(NSString *_Nullable accessToken, NSError *_Nullable error) {
+ if (error) {
+ callback(nil, error);
+ return;
+ }
+ FIRGetAccountInfoRequest *getAccountInfoRequest =
+ [[FIRGetAccountInfoRequest alloc] initWithAPIKey:APIKey accessToken:accessToken];
+ [FIRAuthBackend getAccountInfo:getAccountInfoRequest
+ callback:^(FIRGetAccountInfoResponse *_Nullable response,
+ NSError *_Nullable error) {
+ if (error) {
+ callback(nil, error);
+ return;
+ }
+ user->_anonymous = anonymous;
+ [user updateWithGetAccountInfoResponse:response];
+ callback(user, nil);
+ }];
+ }];
+}
+
+- (nullable instancetype)initWithAPIKey:(NSString *)APIKey {
+ self = [super init];
+ if (self) {
+ _APIKey = [APIKey copy];
+ _providerData = @{ };
+ _taskQueue = [[FIRAuthSerialTaskQueue alloc] init];
+ }
+ return self;
+}
+
+- (nullable instancetype)initWithAPIKey:(NSString *)APIKey
+ tokenService:(FIRSecureTokenService *)tokenService {
+ self = [self initWithAPIKey:APIKey];
+ if (self) {
+ _tokenService = tokenService;
+ }
+ return self;
+}
+
+#pragma mark - NSSecureCoding
+
++ (BOOL)supportsSecureCoding {
+ return YES;
+}
+
+- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder {
+ NSString *userID = [aDecoder decodeObjectOfClass:[NSString class] forKey:kUserIDCodingKey];
+ BOOL hasAnonymousKey = [aDecoder containsValueForKey:kAnonymousCodingKey];
+ BOOL anonymous = [aDecoder decodeBoolForKey:kAnonymousCodingKey];
+ BOOL hasEmailPasswordCredential =
+ [aDecoder decodeBoolForKey:kHasEmailPasswordCredentialCodingKey];
+ NSString *displayName =
+ [aDecoder decodeObjectOfClass:[NSString class] forKey:kDisplayNameCodingKey];
+ NSURL *photoURL =
+ [aDecoder decodeObjectOfClass:[NSURL class] forKey:kPhotoURLCodingKey];
+ NSString *email =
+ [aDecoder decodeObjectOfClass:[NSString class] forKey:kEmailCodingKey];
+ BOOL emailVerified = [aDecoder decodeBoolForKey:kEmailVerifiedCodingKey];
+ NSSet *providerDataClasses = [NSSet setWithArray:@[
+ [NSDictionary class],
+ [NSString class],
+ [FIRUserInfoImpl class]
+ ]];
+ NSDictionary<NSString *, FIRUserInfoImpl *> *providerData =
+ [aDecoder decodeObjectOfClasses:providerDataClasses forKey:kProviderDataKey];
+ NSString *APIKey =
+ [aDecoder decodeObjectOfClass:[NSString class] forKey:kAPIKeyCodingKey];
+ FIRSecureTokenService *tokenService =
+ [aDecoder decodeObjectOfClass:[FIRSecureTokenService class] forKey:kTokenServiceCodingKey];
+ if (!userID || !APIKey || !tokenService) {
+ return nil;
+ }
+ self = [self initWithAPIKey:APIKey];
+ if (self) {
+ _tokenService = tokenService;
+ _userID = userID;
+ // Previous version of this code didn't save 'anonymous' bit directly but deduced it from
+ // 'hasEmailPasswordCredential' and 'providerData' instead, so here backward compatibility is
+ // provided to read old format data.
+ _anonymous = hasAnonymousKey ? anonymous : (!hasEmailPasswordCredential && !providerData.count);
+ _hasEmailPasswordCredential = hasEmailPasswordCredential;
+ _email = email;
+ _emailVerified = emailVerified;
+ _displayName = displayName;
+ _photoURL = photoURL;
+ _providerData = providerData;
+ }
+ return self;
+}
+
+- (void)encodeWithCoder:(NSCoder *)aCoder {
+ [aCoder encodeObject:_userID forKey:kUserIDCodingKey];
+ [aCoder encodeBool:_anonymous forKey:kAnonymousCodingKey];
+ [aCoder encodeBool:_hasEmailPasswordCredential forKey:kHasEmailPasswordCredentialCodingKey];
+ [aCoder encodeObject:_providerData forKey:kProviderDataKey];
+ [aCoder encodeObject:_email forKey:kEmailCodingKey];
+ [aCoder encodeBool:_emailVerified forKey:kEmailVerifiedCodingKey];
+ [aCoder encodeObject:_photoURL forKey:kPhotoURLCodingKey];
+ [aCoder encodeObject:_displayName forKey:kDisplayNameCodingKey];
+ [aCoder encodeObject:_APIKey forKey:kAPIKeyCodingKey];
+ [aCoder encodeObject:_tokenService forKey:kTokenServiceCodingKey];
+}
+
+#pragma mark -
+
+- (NSString *)providerID {
+ return @"Firebase";
+}
+
+- (NSArray<id<FIRUserInfo>> *)providerData {
+ return _providerData.allValues;
+}
+
+/** @fn getAccountInfoRefreshingCache:
+ @brief Gets the users's account data from the server, updating our local values.
+ @param callback Invoked when the request to getAccountInfo has completed, or when an error has
+ been detected. Invoked asynchronously on the auth global work queue in the future.
+ */
+- (void)getAccountInfoRefreshingCache:(void(^)(FIRGetAccountInfoResponseUser *_Nullable user,
+ NSError *_Nullable error))callback {
+ [self internalGetTokenWithCallback:^(NSString *_Nullable accessToken, NSError *_Nullable error) {
+ if (error) {
+ callback(nil, error);
+ return;
+ }
+ FIRGetAccountInfoRequest *getAccountInfoRequest =
+ [[FIRGetAccountInfoRequest alloc] initWithAPIKey:_APIKey accessToken:accessToken];
+ [FIRAuthBackend getAccountInfo:getAccountInfoRequest
+ callback:^(FIRGetAccountInfoResponse *_Nullable response,
+ NSError *_Nullable error) {
+ if (error) {
+ callback(nil, error);
+ return;
+ }
+ [self updateWithGetAccountInfoResponse:response];
+ if (![self updateKeychain:&error]) {
+ callback(nil, error);
+ return;
+ }
+ callback(response.users.firstObject, nil);
+ }];
+ }];
+}
+
+- (void)updateWithGetAccountInfoResponse:(FIRGetAccountInfoResponse *)response {
+ FIRGetAccountInfoResponseUser *user = response.users.firstObject;
+ _userID = user.localID;
+ _email = user.email;
+ _emailVerified = user.emailVerified;
+ _displayName = user.displayName;
+ _photoURL = user.photoURL;
+ _phoneNumber = user.phoneNumber;
+ _hasEmailPasswordCredential = user.passwordHash.length > 0;
+
+ NSMutableDictionary<NSString *, FIRUserInfoImpl *> *providerData =
+ [NSMutableDictionary dictionary];
+ for (FIRGetAccountInfoResponseProviderUserInfo *providerUserInfo in user.providerUserInfo) {
+ FIRUserInfoImpl *userInfo =
+ [FIRUserInfoImpl userInfoWithGetAccountInfoResponseProviderUserInfo:providerUserInfo];
+ if (userInfo) {
+ providerData[providerUserInfo.providerID] = userInfo;
+ }
+ }
+ _providerData = [providerData copy];
+}
+
+/** @fn executeUserUpdateWithChanges:callback:
+ @brief Performs a setAccountInfo request by mutating the results of a getAccountInfo response,
+ atomically in regards to other calls to this method.
+ @param changeBlock A block responsible for mutating a template @c FIRSetAccountInfoRequest
+ @param callback A block to invoke when the change is complete. Invoked asynchronously on the
+ auth global work queue in the future.
+ */
+- (void)executeUserUpdateWithChanges:(void(^)(FIRGetAccountInfoResponseUser *,
+ FIRSetAccountInfoRequest *))changeBlock
+ callback:(nonnull FIRUserProfileChangeCallback)callback {
+ [_taskQueue enqueueTask:^(FIRAuthSerialTaskCompletionBlock _Nonnull complete) {
+ [self getAccountInfoRefreshingCache:^(FIRGetAccountInfoResponseUser *_Nullable user,
+ NSError *_Nullable error) {
+ if (error) {
+ complete();
+ callback(error);
+ return;
+ }
+ [self internalGetTokenWithCallback:^(NSString *_Nullable accessToken,
+ NSError *_Nullable error) {
+ if (error) {
+ complete();
+ callback(error);
+ return;
+ }
+ // Mutate setAccountInfoRequest in block:
+ FIRSetAccountInfoRequest *setAccountInfoRequest =
+ [[FIRSetAccountInfoRequest alloc] initWithAPIKey:_APIKey];
+ setAccountInfoRequest.accessToken = accessToken;
+ changeBlock(user, setAccountInfoRequest);
+ // Execute request:
+ [FIRAuthBackend setAccountInfo:setAccountInfoRequest
+ callback:^(FIRSetAccountInfoResponse *_Nullable response,
+ NSError *_Nullable error) {
+ if (error) {
+ complete();
+ callback(error);
+ return;
+ }
+ if (response.IDToken && response.refreshToken) {
+ FIRSecureTokenService *tokenService =
+ [[FIRSecureTokenService alloc] initWithAPIKey:_APIKey
+ accessToken:response.IDToken
+ accessTokenExpirationDate:response.approximateExpirationDate
+ refreshToken:response.refreshToken];
+ [self setTokenService:tokenService callback:^(NSError *_Nullable error) {
+ complete();
+ callback(error);
+ }];
+ return;
+ }
+ complete();
+ callback(nil);
+ }];
+ }];
+ }];
+ }];
+}
+
+/** @fn updateKeychain:
+ @brief Updates the keychain for user token or info changes.
+ @param error The error if NO is returned.
+ @return Wether the operation is successful.
+ */
+- (BOOL)updateKeychain:(NSError *_Nullable *_Nullable)error {
+ return !_auth || [_auth updateKeychainWithUser:self error:error];
+}
+
+/** @fn setTokenService:callback:
+ @brief Sets a new token service for the @c FIRUser instance.
+ @param tokenService The new token service object.
+ @param callback The block to be called in the global auth working queue once finished.
+ @remarks The method makes sure the token service has access and refresh token and the new tokens
+ are saved in the keychain before calling back.
+ */
+- (void)setTokenService:(FIRSecureTokenService *)tokenService
+ callback:(nonnull CallbackWithError)callback {
+ [tokenService fetchAccessTokenForcingRefresh:NO
+ callback:^(NSString *_Nullable token,
+ NSError *_Nullable error,
+ BOOL tokenUpdated) {
+ if (error) {
+ callback(error);
+ return;
+ }
+ _tokenService = tokenService;
+ if (![self updateKeychain:&error]) {
+ callback(error);
+ return;
+ }
+ [_auth notifyListenersOfAuthStateChangeWithUser:self token:token];
+ callback(nil);
+ }];
+}
+
+#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
+ address.
+ @param email The email address for the user, if to be updated.
+ @param password The new password for the user, if to be updated.
+ @param callback The block called when the user profile change has finished. Invoked
+ asynchronously on the auth global work queue in the future.
+ @remarks May fail with a @c FIRAuthErrorCodeRequiresRecentLogin error code.
+ Call @c reauthentateWithCredential:completion: beforehand to avoid this error case.
+ */
+- (void)updateEmail:(nullable NSString *)email
+ password:(nullable NSString *)password
+ callback:(nonnull FIRUserProfileChangeCallback)callback {
+ if (password && ![password length]){
+ callback([FIRAuthErrorUtils weakPasswordErrorWithServerResponseReason:kMissingPasswordReason]);
+ return;
+ }
+ BOOL hadEmailPasswordCredential = _hasEmailPasswordCredential;
+ [self executeUserUpdateWithChanges:^(FIRGetAccountInfoResponseUser *user,
+ FIRSetAccountInfoRequest *request) {
+ if (email) {
+ request.email = email;
+ }
+ if (password) {
+ request.password = password;
+ }
+ }
+ callback:^(NSError *error) {
+ if (error) {
+ callback(error);
+ return;
+ }
+ if (email) {
+ _email = email;
+ }
+ if (_email && password) {
+ _anonymous = NO;
+ _hasEmailPasswordCredential = YES;
+ if (!hadEmailPasswordCredential) {
+ // The list of providers need to be updated for the newly added email-password provider.
+ [self internalGetTokenWithCallback:^(NSString *_Nullable accessToken,
+ NSError *_Nullable error) {
+ if (error) {
+ callback(error);
+ return;
+ }
+ FIRGetAccountInfoRequest *getAccountInfoRequest =
+ [[FIRGetAccountInfoRequest alloc] initWithAPIKey:_APIKey accessToken:accessToken];
+ [FIRAuthBackend getAccountInfo:getAccountInfoRequest
+ callback:^(FIRGetAccountInfoResponse *_Nullable response,
+ NSError *_Nullable error) {
+ if (error) {
+ callback(error);
+ return;
+ }
+ [self updateWithGetAccountInfoResponse:response];
+ if (![self updateKeychain:&error]) {
+ callback(error);
+ return;
+ }
+ callback(nil);
+ }];
+ }];
+ return;
+ }
+ }
+ if (![self updateKeychain:&error]) {
+ callback(error);
+ return;
+ }
+ callback(nil);
+ }];
+}
+
+- (void)updateEmail:(NSString *)email completion:(nullable FIRUserProfileChangeCallback)completion {
+ dispatch_async(FIRAuthGlobalWorkQueue(), ^{
+ [self updateEmail:email password:nil callback:^(NSError *_Nullable error) {
+ callInMainThreadWithError(completion, error);
+ }];
+ });
+}
+
+- (void)updatePassword:(NSString *)password
+ completion:(nullable FIRUserProfileChangeCallback)completion {
+ dispatch_async(FIRAuthGlobalWorkQueue(), ^{
+ [self updateEmail:nil password:password callback:^(NSError *_Nullable error){
+ callInMainThreadWithError(completion, error);
+ }];
+ });
+}
+
+/** @fn internalUpdatePhoneNumberCredential:completion:
+ @brief Updates the phone number for the user. On success, the cached user profile data is
+ updated.
+
+ @param phoneAuthCredential The new phone number credential corresponding to the phone number
+ to be added to the firebaes account, if a phone number is already linked to the account this
+ new phone number will replace it.
+ @param completion Optionally; the block invoked when the user profile change has finished.
+ Invoked asynchronously on the global work queue in the future.
+ */
+- (void)internalUpdatePhoneNumberCredential:(FIRPhoneAuthCredential *)phoneAuthCredential
+ completion:(FIRUserProfileChangeCallback)completion {
+ [self internalGetTokenWithCallback:^(NSString *_Nullable accessToken,
+ NSError *_Nullable error) {
+ if (error) {
+ completion(error);
+ return;
+ }
+ FIRVerifyPhoneNumberRequest *request = [[FIRVerifyPhoneNumberRequest alloc]
+ initWithVerificationID:phoneAuthCredential.verificationID
+ verificationCode:phoneAuthCredential.verificationCode
+ APIKey:_APIKey];
+ request.accessToken = accessToken;
+ [FIRAuthBackend verifyPhoneNumber:request
+ callback:^(FIRVerifyPhoneNumberResponse *_Nullable response,
+ NSError *_Nullable error) {
+ if (error) {
+ completion(error);;
+ return;
+ }
+ // Get account info to update cached user info.
+ [self getAccountInfoRefreshingCache:^(FIRGetAccountInfoResponseUser *_Nullable user,
+ NSError *_Nullable error) {
+ if (![self updateKeychain:&error]) {
+ completion(error);
+ return;
+ }
+ completion(nil);
+ }];
+ }];
+ }];
+}
+
+- (void)updatePhoneNumberCredential:(FIRPhoneAuthCredential *)phoneAuthCredential
+ completion:(nullable FIRUserProfileChangeCallback)completion {
+ dispatch_async(FIRAuthGlobalWorkQueue(), ^{
+ [self internalUpdatePhoneNumberCredential:phoneAuthCredential
+ completion:^(NSError *_Nullable error) {
+ callInMainThreadWithError(completion, error);
+ }];
+ });
+}
+
+- (FIRUserProfileChangeRequest *)profileChangeRequest {
+ __block FIRUserProfileChangeRequest *result;
+ dispatch_sync(FIRAuthGlobalWorkQueue(), ^{
+ result = [[FIRUserProfileChangeRequest alloc] initWithUser:self];
+ });
+ return result;
+}
+
+- (void)setDisplayName:(NSString *)displayName {
+ _displayName = [displayName copy];
+}
+
+- (void)setPhotoURL:(NSURL *)photoURL {
+ _photoURL = [photoURL copy];
+}
+
+- (NSString *)rawAccessToken {
+ return _tokenService.rawAccessToken;
+}
+
+- (NSDate *)accessTokenExpirationDate {
+ return _tokenService.accessTokenExpirationDate;
+}
+
+#pragma mark -
+
+- (void)reloadWithCompletion:(nullable FIRUserProfileChangeCallback)completion {
+ dispatch_async(FIRAuthGlobalWorkQueue(), ^{
+ [self getAccountInfoRefreshingCache:^(FIRGetAccountInfoResponseUser *_Nullable user,
+ NSError *_Nullable error) {
+ callInMainThreadWithError(completion, error);
+ }];
+ });
+}
+
+#pragma mark -
+
+- (void)reauthenticateWithCredential:(FIRAuthCredential *)credential
+ completion:(nullable FIRUserProfileChangeCallback)completion {
+ FIRAuthDataResultCallback callback = ^(FIRAuthDataResult *_Nullable authResult,
+ NSError *_Nullable error) {
+ completion(error);
+ };
+ [self reauthenticateAndRetrieveDataWithCredential:credential completion:callback];
+}
+
+- (void)
+ reauthenticateAndRetrieveDataWithCredential:(FIRAuthCredential *) credential
+ completion:(nullable FIRAuthDataResultCallback) completion {
+ dispatch_async(FIRAuthGlobalWorkQueue(), ^{
+ [_auth internalSignInAndRetrieveDataWithCredential:credential
+ isReauthentication:YES
+ callback:^(FIRAuthDataResult *_Nullable authResult,
+ NSError *_Nullable error) {
+ if (error) {
+ // If "user not found" error returned by backend, translate to user mismatch error which is
+ // more accurate.
+ if (error.code == FIRAuthErrorCodeUserNotFound) {
+ error = [FIRAuthErrorUtils userMismatchError];
+ }
+ callInMainThreadWithAuthDataResultAndError(completion, authResult, error);
+ return;
+ }
+ if (![authResult.user.uid isEqual:_auth.currentUser.uid]) {
+ callInMainThreadWithAuthDataResultAndError(completion, authResult,
+ [FIRAuthErrorUtils userMismatchError]);
+ return;
+ }
+ // Successful reauthenticate
+ [self setTokenService:authResult.user->_tokenService callback:^(NSError *_Nullable error) {
+ callInMainThreadWithAuthDataResultAndError(completion, authResult, error);
+ }];
+ }];
+ });
+}
+
+- (nullable NSString *)refreshToken {
+ __block NSString *result;
+ dispatch_sync(FIRAuthGlobalWorkQueue(), ^{
+ result = _tokenService.refreshToken;
+ });
+ return result;
+}
+
+- (void)getIDTokenWithCompletion:(nullable FIRAuthTokenCallback)completion {
+ // |getTokenForcingRefresh:completion:| is also a public API so there is no need to dispatch to
+ // global work queue here.
+ [self getIDTokenForcingRefresh:NO completion:completion];
+}
+
+- (void)getTokenWithCompletion:(nullable FIRAuthTokenCallback)completion {
+ [self getIDTokenWithCompletion:completion];
+}
+
+- (void)getIDTokenForcingRefresh:(BOOL)forceRefresh
+ completion:(nullable FIRAuthTokenCallback)completion {
+ dispatch_async(FIRAuthGlobalWorkQueue(), ^{
+ [self internalGetTokenForcingRefresh:forceRefresh
+ callback:^(NSString *_Nullable token, NSError *_Nullable error) {
+ if (completion) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ completion(token, error);
+ });
+ }
+ }];
+ });
+}
+
+- (void)getTokenForcingRefresh:(BOOL)forceRefresh
+ completion:(nullable FIRAuthTokenCallback)completion {
+ [self getIDTokenForcingRefresh:forceRefresh completion:completion];
+}
+
+/** @fn internalGetTokenForcingRefresh:callback:
+ @brief Retrieves the Firebase authentication token, possibly refreshing it if it has expired.
+ @param callback The block to invoke when the token is available. Invoked asynchronously on the
+ global work thread in the future.
+ */
+- (void)internalGetTokenWithCallback:(nonnull FIRAuthTokenCallback)callback {
+ [self internalGetTokenForcingRefresh:NO callback:callback];
+}
+
+- (void)internalGetTokenForcingRefresh:(BOOL)forceRefresh
+ callback:(nonnull FIRAuthTokenCallback)callback {
+ [_tokenService fetchAccessTokenForcingRefresh:forceRefresh
+ callback:^(NSString *_Nullable token,
+ NSError *_Nullable error,
+ BOOL tokenUpdated) {
+ if (error) {
+ callback(nil, error);
+ return;
+ }
+ if (tokenUpdated) {
+ if (![self updateKeychain:&error]) {
+ callback(nil, error);
+ return;
+ }
+ [_auth notifyListenersOfAuthStateChangeWithUser:self token:token];
+ }
+ callback(token, nil);
+ }];
+}
+
+- (void)linkWithCredential:(FIRAuthCredential *)credential
+ completion:(nullable FIRAuthResultCallback)completion {
+ FIRAuthDataResultCallback callback = ^(FIRAuthDataResult *_Nullable authResult,
+ NSError *_Nullable error) {
+ completion(authResult.user, error);
+ };
+ [self linkAndRetrieveDataWithCredential:credential completion:callback];
+}
+
+- (void)linkAndRetrieveDataWithCredential:(FIRAuthCredential *)credential
+ completion:(nullable FIRAuthDataResultCallback)completion {
+ dispatch_async(FIRAuthGlobalWorkQueue(), ^{
+ if (_providerData[credential.provider]) {
+ callInMainThreadWithAuthDataResultAndError(completion,
+ nil,
+ [FIRAuthErrorUtils providerAlreadyLinkedError]);
+ return;
+ }
+ FIRAuthDataResult *result =
+ [[FIRAuthDataResult alloc] initWithUser:self additionalUserInfo:nil];
+ if ([credential isKindOfClass:[FIREmailPasswordAuthCredential class]]) {
+ if (_hasEmailPasswordCredential) {
+ callInMainThreadWithAuthDataResultAndError(completion,
+ nil,
+ [FIRAuthErrorUtils providerAlreadyLinkedError]);
+ return;
+ }
+ FIREmailPasswordAuthCredential *emailPasswordCredential =
+ (FIREmailPasswordAuthCredential *)credential;
+ [self updateEmail:emailPasswordCredential.email
+ password:emailPasswordCredential.password
+ callback:^(NSError *error) {
+ if (error) {
+ callInMainThreadWithAuthDataResultAndError(completion, nil, error);
+ } else {
+ callInMainThreadWithAuthDataResultAndError(completion, result, nil);
+ }
+ }];
+ return;
+ }
+
+ if ([credential isKindOfClass:[FIRPhoneAuthCredential class]]) {
+ FIRPhoneAuthCredential *phoneAuthCredential = (FIRPhoneAuthCredential *)credential;
+ [self internalUpdatePhoneNumberCredential:phoneAuthCredential
+ completion:^(NSError *_Nullable error) {
+ if (error){
+ callInMainThreadWithAuthDataResultAndError(completion, nil, error);
+ } else {
+ callInMainThreadWithAuthDataResultAndError(completion, result, nil);
+ }
+ }];
+ return;
+ }
+
+ [_taskQueue enqueueTask:^(FIRAuthSerialTaskCompletionBlock _Nonnull complete) {
+ CallbackWithAuthDataResultAndError completeWithError =
+ ^(FIRAuthDataResult *result, NSError *error) {
+ complete();
+ callInMainThreadWithAuthDataResultAndError(completion, result, error);
+ };
+ [self internalGetTokenWithCallback:^(NSString *_Nullable accessToken,
+ NSError *_Nullable error) {
+ if (error) {
+ completeWithError(nil, error);
+ return;
+ }
+ FIRVerifyAssertionRequest *request =
+ [[FIRVerifyAssertionRequest alloc] initWithAPIKey:_APIKey providerID:credential.provider];
+ [credential prepareVerifyAssertionRequest:request];
+ request.accessToken = accessToken;
+ [FIRAuthBackend verifyAssertion:request
+ callback:^(FIRVerifyAssertionResponse *response, NSError *error) {
+ if (error) {
+ completeWithError(nil, error);
+ return;
+ }
+ FIRAdditionalUserInfo *additionalUserInfo =
+ [FIRAdditionalUserInfo userInfoWithVerifyAssertionResponse:response];
+ FIRAuthDataResult *result =
+ [[FIRAuthDataResult alloc] initWithUser:self additionalUserInfo:additionalUserInfo];
+ // Update the new token and refresh user info again.
+ _tokenService =
+ [[FIRSecureTokenService alloc] initWithAPIKey:_APIKey
+ accessToken:response.IDToken
+ accessTokenExpirationDate:response.approximateExpirationDate
+ refreshToken:response.refreshToken];
+ [self internalGetTokenWithCallback:^(NSString *_Nullable accessToken,
+ NSError *_Nullable error) {
+ if (error) {
+ completeWithError(nil, error);
+ return;
+ }
+ FIRGetAccountInfoRequest *getAccountInfoRequest =
+ [[FIRGetAccountInfoRequest alloc] initWithAPIKey:_APIKey accessToken:accessToken];
+ [FIRAuthBackend getAccountInfo:getAccountInfoRequest
+ callback:^(FIRGetAccountInfoResponse *_Nullable response,
+ NSError *_Nullable error) {
+ if (error) {
+ completeWithError(nil, error);
+ return;
+ }
+ _anonymous = NO;
+ [self updateWithGetAccountInfoResponse:response];
+ if (![self updateKeychain:&error]) {
+ completeWithError(nil, error);
+ return;
+ }
+ completeWithError(result, nil);
+ }];
+ }];
+ }];
+ }];
+ }];
+ });
+}
+
+- (void)unlinkFromProvider:(NSString *)provider
+ completion:(nullable FIRAuthResultCallback)completion {
+ [_taskQueue enqueueTask:^(FIRAuthSerialTaskCompletionBlock _Nonnull complete) {
+ CallbackWithError completeAndCallbackWithError = ^(NSError *error) {
+ complete();
+ callInMainThreadWithUserAndError(completion, self, error);
+ };
+ [self internalGetTokenWithCallback:^(NSString *_Nullable accessToken,
+ NSError *_Nullable error) {
+ if (error) {
+ completeAndCallbackWithError(error);
+ return;
+ }
+ FIRSetAccountInfoRequest *setAccountInfoRequest =
+ [[FIRSetAccountInfoRequest alloc] initWithAPIKey:_APIKey];
+ setAccountInfoRequest.accessToken = accessToken;
+ BOOL isEmailPasswordProvider = [provider isEqualToString:FIREmailAuthProviderID];
+ if (isEmailPasswordProvider) {
+ if (!_hasEmailPasswordCredential) {
+ completeAndCallbackWithError([FIRAuthErrorUtils noSuchProviderError]);
+ return;
+ }
+ setAccountInfoRequest.deleteAttributes = @[ FIRSetAccountInfoUserAttributePassword ];
+ } else {
+ if (!_providerData[provider]) {
+ completeAndCallbackWithError([FIRAuthErrorUtils noSuchProviderError]);
+ return;
+ }
+ setAccountInfoRequest.deleteProviders = @[ provider ];
+ }
+ [FIRAuthBackend setAccountInfo:setAccountInfoRequest
+ callback:^(FIRSetAccountInfoResponse *_Nullable response,
+ NSError *_Nullable error) {
+ if (error) {
+ completeAndCallbackWithError(error);
+ return;
+ }
+ if (isEmailPasswordProvider) {
+ _hasEmailPasswordCredential = NO;
+ } else {
+ // We can't just use the provider info objects in FIRSetAcccountInfoResponse because they
+ // don't have localID and email fields. Remove the specific provider manually.
+ NSMutableDictionary *mutableProviderData = [_providerData mutableCopy];
+ [mutableProviderData removeObjectForKey:provider];
+ _providerData = [mutableProviderData copy];
+
+ // After successfully unlinking a phone auth provider, remove the phone number from the
+ // cached user info.
+ if ([provider isEqualToString:FIRPhoneAuthProviderID]) {
+ _phoneNumber = nil;
+ }
+ }
+ if (response.IDToken && response.refreshToken) {
+ FIRSecureTokenService *tokenService =
+ [[FIRSecureTokenService alloc] initWithAPIKey:_APIKey
+ accessToken:response.IDToken
+ accessTokenExpirationDate:response.approximateExpirationDate
+ refreshToken:response.refreshToken];
+ [self setTokenService:tokenService callback:^(NSError *_Nullable error) {
+ completeAndCallbackWithError(error);
+ }];
+ return;
+ }
+ if (![self updateKeychain:&error]) {
+ completeAndCallbackWithError(error);
+ return;
+ }
+ completeAndCallbackWithError(nil);
+ }];
+ }];
+ }];
+}
+
+- (void)sendEmailVerificationWithCompletion:(nullable FIRSendEmailVerificationCallback)completion {
+ dispatch_async(FIRAuthGlobalWorkQueue(), ^{
+ [self internalGetTokenWithCallback:^(NSString *_Nullable accessToken,
+ NSError *_Nullable error) {
+ if (error) {
+ callInMainThreadWithError(completion, error);
+ return;
+ }
+ FIRGetOOBConfirmationCodeRequest *request =
+ [FIRGetOOBConfirmationCodeRequest verifyEmailRequestWithAccessToken:accessToken
+ APIKey:_APIKey];
+ [FIRAuthBackend getOOBConfirmationCode:request
+ callback:^(FIRGetOOBConfirmationCodeResponse *_Nullable
+ response,
+ NSError *_Nullable error) {
+ callInMainThreadWithError(completion, error);
+ }];
+ }];
+ });
+}
+
+- (void)deleteWithCompletion:(nullable FIRUserProfileChangeCallback)completion {
+ dispatch_async(FIRAuthGlobalWorkQueue(), ^{
+ [self internalGetTokenWithCallback:^(NSString *_Nullable accessToken,
+ NSError *_Nullable error) {
+ if (error) {
+ callInMainThreadWithError(completion, error);
+ return;
+ }
+ FIRDeleteAccountRequest *deleteUserRequest =
+ [[FIRDeleteAccountRequest alloc] initWithAPIKey:_APIKey
+ localID:_userID
+ accessToken:accessToken];
+ [FIRAuthBackend deleteAccount:deleteUserRequest callback:^(NSError *_Nullable error) {
+ if (error) {
+ callInMainThreadWithError(completion, error);
+ return;
+ }
+ if (![[FIRAuth auth] signOutByForceWithUserID:_userID error:&error]) {
+ callInMainThreadWithError(completion, error);
+ return;
+ }
+ callInMainThreadWithError(completion, error);
+ }];
+ }];
+ });
+}
+
+@end
+
+@implementation FIRUserProfileChangeRequest {
+ /** @var _user
+ @brief The user associated with the change request.
+ */
+ FIRUser *_user;
+
+ /** @var _displayName
+ @brief The display name value to set if @c _displayNameSet is YES.
+ */
+ NSString *_displayName;
+
+ /** @var _displayNameSet
+ @brief Indicates the display name should be part of the change request.
+ */
+ BOOL _displayNameSet;
+
+ /** @var _photoURL
+ @brief The photo URL value to set if @c _displayNameSet is YES.
+ */
+ NSURL *_photoURL;
+
+ /** @var _photoURLSet
+ @brief Indicates the photo URL should be part of the change request.
+ */
+ BOOL _photoURLSet;
+
+ /** @var _consumed
+ @brief Indicates the @c commitChangesWithCallback: method has already been invoked.
+ */
+ BOOL _consumed;
+}
+
+- (nullable instancetype)initWithUser:(FIRUser *)user {
+ self = [super init];
+ if (self) {
+ _user = user;
+ }
+ return self;
+}
+
+- (nullable NSString *)displayName {
+ return _displayName;
+}
+
+- (void)setDisplayName:(nullable NSString *)displayName {
+ dispatch_sync(FIRAuthGlobalWorkQueue(), ^{
+ if (_consumed) {
+ [NSException raise:NSInternalInconsistencyException
+ format:@"%@",
+ @"Invalid call to setDisplayName: after commitChangesWithCallback:."];
+ return;
+ }
+ _displayNameSet = YES;
+ _displayName = [displayName copy];
+ });
+}
+
+- (nullable NSURL *)photoURL {
+ return _photoURL;
+}
+
+- (void)setPhotoURL:(nullable NSURL *)photoURL {
+ dispatch_sync(FIRAuthGlobalWorkQueue(), ^{
+ if (_consumed) {
+ [NSException raise:NSInternalInconsistencyException
+ format:@"%@",
+ @"Invalid call to setPhotoURL: after commitChangesWithCallback:."];
+ return;
+ }
+ _photoURLSet = YES;
+ _photoURL = [photoURL copy];
+ });
+}
+
+/** @fn hasUpdates
+ @brief Indicates at least one field has a value which needs to be committed.
+ */
+- (BOOL)hasUpdates {
+ return _displayNameSet || _photoURLSet;
+}
+
+- (void)commitChangesWithCompletion:(nullable FIRUserProfileChangeCallback)completion {
+ dispatch_sync(FIRAuthGlobalWorkQueue(), ^{
+ if (_consumed) {
+ [NSException raise:NSInternalInconsistencyException
+ format:@"%@",
+ @"commitChangesWithCallback: should only be called once."];
+ return;
+ }
+ _consumed = YES;
+ // Return fast if there is nothing to update:
+ if (![self hasUpdates]) {
+ callInMainThreadWithError(completion, nil);
+ return;
+ }
+ NSString *displayName = [_displayName copy];
+ BOOL displayNameWasSet = _displayNameSet;
+ NSURL *photoURL = [_photoURL copy];
+ BOOL photoURLWasSet = _photoURLSet;
+ [_user executeUserUpdateWithChanges:^(FIRGetAccountInfoResponseUser *user,
+ FIRSetAccountInfoRequest *request) {
+ if (photoURLWasSet) {
+ request.photoURL = photoURL;
+ }
+ if (displayNameWasSet) {
+ request.displayName = displayName;
+ }
+ }
+ callback:^(NSError *_Nullable error) {
+ if (error) {
+ callInMainThreadWithError(completion, error);
+ return;
+ }
+ if (displayNameWasSet) {
+ [_user setDisplayName:displayName];
+ }
+ if (photoURLWasSet) {
+ [_user setPhotoURL:photoURL];
+ }
+ if (![_user updateKeychain:&error]) {
+ callInMainThreadWithError(completion, error);
+ return;
+ }
+ callInMainThreadWithError(completion, nil);
+ }];
+ });
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/FIRUserInfo.h b/Firebase/Auth/Source/FIRUserInfo.h
new file mode 100644
index 0000000..03f2038
--- /dev/null
+++ b/Firebase/Auth/Source/FIRUserInfo.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "FIRAuthSwiftNameSupport.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ @brief Represents user data returned from an identity provider.
+ */
+FIR_SWIFT_NAME(UserInfo)
+@protocol FIRUserInfo <NSObject>
+
+/** @property providerID
+ @brief The provider identifier.
+ */
+@property(nonatomic, copy, readonly) NSString *providerID;
+
+/** @property uid
+ @brief The provider's user ID for the user.
+ */
+@property(nonatomic, copy, readonly) NSString *uid;
+
+/** @property displayName
+ @brief The name of the user.
+ */
+@property(nonatomic, copy, readonly, nullable) NSString *displayName;
+
+/** @property photoURL
+ @brief The URL of the user's profile photo.
+ */
+@property(nonatomic, copy, readonly, nullable) NSURL *photoURL;
+
+/** @property email
+ @brief The user's email address.
+ */
+@property(nonatomic, copy, readonly, nullable) NSString *email;
+
+/** @property phoneNumber
+ @brief A phone number associated with the user.
+ @remarks This property is only available for users authenticated via phone number auth.
+ */
+@property(nonatomic, readonly, nullable) NSString *phoneNumber;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/FIRUserInfoImpl.h b/Firebase/Auth/Source/FIRUserInfoImpl.h
new file mode 100644
index 0000000..0022a68
--- /dev/null
+++ b/Firebase/Auth/Source/FIRUserInfoImpl.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "FIRUserInfo.h"
+
+@class FIRGetAccountInfoResponseProviderUserInfo;
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface FIRUserInfoImpl : NSObject <FIRUserInfo, NSSecureCoding>
+
+/** @fn userInfoWithGetAccountInfoResponseProviderUserInfo:
+ @brief A convenience factory method for constructing a @c FIRUserInfo instance from data
+ returned by the getAccountInfo endpoint.
+ @param providerUserInfo Data returned by the getAccountInfo endpoint.
+ @return A new instance of @c FIRUserInfo using data from the getAccountInfo endpoint.
+ */
++ (nullable instancetype)userInfoWithGetAccountInfoResponseProviderUserInfo:
+ (FIRGetAccountInfoResponseProviderUserInfo *)providerUserInfo;
+
+/** @fn init
+ @brief This class should not be initialized manually.
+ @see FIRUser.providerData
+ */
+- (instancetype)init NS_UNAVAILABLE;
+
+/** @fn initWithProviderID:userID:displayName:photoURL:email:
+ @brief Designated initializer.
+ @param providerID The provider identifier.
+ @param userID The unique user ID for the user (the value of the @c uid field in the token.)
+ @param displayName The name of the user.
+ @param photoURL The URL of the user's profile photo.
+ @param email The user's email address.
+ @param phoneNumber The user's phone number.
+ */
+- (nullable instancetype)initWithProviderID:(NSString *)providerID
+ userID:(NSString *)userID
+ displayName:(nullable NSString *)displayName
+ photoURL:(nullable NSURL *)photoURL
+ email:(nullable NSString *)email
+ phoneNumber:(nullable NSString *)phoneNumber
+ NS_DESIGNATED_INITIALIZER;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/FIRUserInfoImpl.m b/Firebase/Auth/Source/FIRUserInfoImpl.m
new file mode 100644
index 0000000..d172481
--- /dev/null
+++ b/Firebase/Auth/Source/FIRUserInfoImpl.m
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRUserInfoImpl.h"
+
+#import "FIRGetAccountInfoResponse.h"
+
+/** @var kProviderIDCodingKey
+ @brief The key used to encode the providerID property for NSSecureCoding.
+ */
+static NSString *const kProviderIDCodingKey = @"providerID";
+
+/** @var kUserIDCodingKey
+ @brief The key used to encode the userID property for NSSecureCoding.
+ */
+static NSString *const kUserIDCodingKey = @"userID";
+
+/** @var kDisplayNameCodingKey
+ @brief The key used to encode the displayName property for NSSecureCoding.
+ */
+static NSString *const kDisplayNameCodingKey = @"displayName";
+
+/** @var kProfileURLCodingKey
+ @brief The key used to encode the profileURL property for NSSecureCoding.
+ */
+static NSString *const kProfileURLCodingKey = @"profileURL";
+
+/** @var kPhotoURLCodingKey
+ @brief The key used to encode the photoURL property for NSSecureCoding.
+ */
+static NSString *const kPhotoURLCodingKey = @"photoURL";
+
+/** @var kEmailCodingKey
+ @brief The key used to encode the email property for NSSecureCoding.
+ */
+static NSString *const kEmailCodingKey = @"email";
+
+/** @var kPhoneNumberCodingKey
+ @brief The key used to encode the phoneNumber property for NSSecureCoding.
+ */
+static NSString *const kPhoneNumberCodingKey = @"phoneNumber";
+
+@implementation FIRUserInfoImpl
+
+@synthesize providerID = _providerID;
+@synthesize uid = _userID;
+@synthesize displayName = _displayName;
+@synthesize photoURL = _photoURL;
+@synthesize email = _email;
+@synthesize phoneNumber = _phoneNumber;
+
++ (nullable instancetype)userInfoWithGetAccountInfoResponseProviderUserInfo:
+ (FIRGetAccountInfoResponseProviderUserInfo *)providerUserInfo {
+ return [[self alloc] initWithProviderID:providerUserInfo.providerID
+ userID:providerUserInfo.federatedID
+ displayName:providerUserInfo.displayName
+ photoURL:providerUserInfo.photoURL
+ email:providerUserInfo.email
+ phoneNumber:providerUserInfo.phoneNumber];
+}
+
+- (nullable instancetype)initWithProviderID:(NSString *)providerID
+ userID:(NSString *)userID
+ displayName:(nullable NSString *)displayName
+ photoURL:(nullable NSURL *)photoURL
+ email:(nullable NSString *)email
+ phoneNumber:(nullable NSString *)phoneNumber {
+ self = [super init];
+ if (self) {
+ _providerID = [providerID copy];
+ _userID = [userID copy];
+ _displayName = [displayName copy];
+ _photoURL = [photoURL copy];
+ _email = [email copy];
+ _phoneNumber = [phoneNumber copy];
+ }
+ return self;
+}
+
+#pragma mark - NSSecureCoding
+
++ (BOOL)supportsSecureCoding {
+ return YES;
+}
+
+- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder {
+ NSString *providerID =
+ [aDecoder decodeObjectOfClass:[NSString class] forKey:kProviderIDCodingKey];
+ NSString *userID = [aDecoder decodeObjectOfClass:[NSString class] forKey:kUserIDCodingKey];
+ NSString *displayName =
+ [aDecoder decodeObjectOfClass:[NSString class] forKey:kDisplayNameCodingKey];
+ NSURL *photoURL = [aDecoder decodeObjectOfClass:[NSURL class] forKey:kPhotoURLCodingKey];
+ NSString *email = [aDecoder decodeObjectOfClass:[NSString class] forKey:kEmailCodingKey];
+ NSString *phoneNumber =
+ [aDecoder decodeObjectOfClass:[NSString class] forKey:kPhoneNumberCodingKey];
+
+ return [self initWithProviderID:providerID
+ userID:userID
+ displayName:displayName
+ photoURL:photoURL
+ email:email
+ phoneNumber:phoneNumber];
+}
+
+- (void)encodeWithCoder:(NSCoder *)aCoder {
+ [aCoder encodeObject:_providerID forKey:kProviderIDCodingKey];
+ [aCoder encodeObject:_userID forKey:kUserIDCodingKey];
+ [aCoder encodeObject:_displayName forKey:kDisplayNameCodingKey];
+ [aCoder encodeObject:_photoURL forKey:kPhotoURLCodingKey];
+ [aCoder encodeObject:_email forKey:kEmailCodingKey];
+ [aCoder encodeObject:_phoneNumber forKey:kPhoneNumberCodingKey];
+}
+
+@end
diff --git a/Firebase/Auth/Source/FirebaseAuth.h b/Firebase/Auth/Source/FirebaseAuth.h
new file mode 100644
index 0000000..8dba24e
--- /dev/null
+++ b/Firebase/Auth/Source/FirebaseAuth.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIREmailAuthProvider.h"
+#import "FIRFacebookAuthProvider.h"
+#import "FIRGitHubAuthProvider.h"
+#import "FIRGoogleAuthProvider.h"
+#import "FIRTwitterAuthProvider.h"
+#import "FIRAuth.h"
+#import "FIRAuthCredential.h"
+#import "FIRAuthErrors.h"
+#import "FIRUser.h"
+#import "FIRUserInfo.h"
+#import "FirebaseAuthVersion.h"
diff --git a/Firebase/Auth/Source/FirebaseAuthVersion.h b/Firebase/Auth/Source/FirebaseAuthVersion.h
new file mode 100755
index 0000000..1b2d06a
--- /dev/null
+++ b/Firebase/Auth/Source/FirebaseAuthVersion.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+/**
+ Version number for FirebaseAuth.
+ */
+extern const double FirebaseAuthVersionNumber;
+
+/**
+ Version string for FirebaseAuth.
+ */
+extern const unsigned char *const FirebaseAuthVersionString;
diff --git a/Firebase/Auth/Source/FirebaseAuthVersion.m b/Firebase/Auth/Source/FirebaseAuthVersion.m
new file mode 100644
index 0000000..fe4055b
--- /dev/null
+++ b/Firebase/Auth/Source/FirebaseAuthVersion.m
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FirebaseAuthVersion.h"
+
+// Convert the macro to a string
+#define STR(x) STR_EXPAND(x)
+#define STR_EXPAND(x) #x
+
+const double FirebaseAuthVersionNumber = FIRAuth_MINOR_VERSION;
+
+const unsigned char *const FirebaseAuthVersionString =
+ (const unsigned char *const)STR(FIRAuth_VERSION);
diff --git a/Firebase/Auth/Source/Private/FIRActionCodeSettings.h b/Firebase/Auth/Source/Private/FIRActionCodeSettings.h
new file mode 100644
index 0000000..adb9cbc
--- /dev/null
+++ b/Firebase/Auth/Source/Private/FIRActionCodeSettings.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @class FIRActionCodeSettings
+ @brief Used to set and retrieve settings related to the handling action codes.
+ */
+@interface FIRActionCodeSettings : NSObject
+
+/** @property URL
+ @brief This URL represents the state/Continue URL in the form of a universal link.
+ @remarks This URL can should be contructed as a universal link that would either directly open
+ the app where the action code would be handled or continue to the app after the action code
+ handled by Firebase.
+ */
+@property(nonatomic, copy, nullable) NSURL *URL;
+
+/** @property handleCodeInApp
+ @brief Indicates whether or not the action code link will open the app directly or after being
+ redirected from a Firebase owned web widget.
+ */
+@property(assign, nonatomic) BOOL handleCodeInApp;
+
+/** @property iOSBundleID
+ @brief The iOS bundle ID, if available.
+ */
+@property(copy, nonatomic, readonly, nullable) NSString *iOSBundleID;
+
+/** @property iOSAppStoreID
+ @brief The iOS app store identifier, if available.
+ */
+@property(nonatomic, copy, readonly, nullable) NSString *iOSAppStoreID;
+
+/** @property androidPackageName
+ @brief The Android package name, if available.
+ */
+@property(nonatomic, copy, readonly, nullable) NSString *androidPackageName;
+
+/** @property androidMinimumVersion
+ @brief The minimum Android version supported, if available.
+ */
+@property(nonatomic, copy, readonly, nullable) NSString *androidMinimumVersion;
+
+/** @property androidInstallIfNotAvailable
+ @brief Indicates whether or not the Android app should be installed if not already available.
+ */
+@property(nonatomic, assign, readonly) BOOL androidInstallIfNotAvailable;
+
+/** @fn setIOSBundleID:appStoreID
+ @brief Sets the iOS bundle Id and appStoreID.
+ @param iOSBundleID The iOS bundle ID.
+ @param appStoreID The app's AppStore ID.
+ @remarks If the app is not already installed on an iOS device and an appStoreId is provided, the
+ app store page of the app will be opened. If no app store ID is provided, the web app link
+ will be used instead.
+ */
+- (void)setIOSBundleID:(NSString *)iOSBundleID appStoreID:(nullable NSString *)appStoreID;
+
+/** @fn setAndroidPackageName:installIfNotAvailable:minimumVersion:
+ @brief Sets the Android package name, the flag to indicate whether or not to install the app and
+ the minimum Android version supported.
+ @param androidPackageName The Android package name.
+ @param installIfNotAvailable Indicates whether or not the app should be installed if not
+ available.
+ @param minimumVersion The minimum version of Android supported.
+ @remarks If installIfNotAvailable is set to YES and the link is opened on an android device, it
+ will try to install the app if not already available. Otherwise the web URL is used.
+ */
+- (void)setAndroidPackageName:(NSString *)androidPackageName
+ installIfNotAvailable:(BOOL)installIfNotAvailable
+ minimumVersion:(nullable NSString *)minimumVersion;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/Private/FIRAdditionalUserInfo_Internal.h b/Firebase/Auth/Source/Private/FIRAdditionalUserInfo_Internal.h
new file mode 100644
index 0000000..a813566
--- /dev/null
+++ b/Firebase/Auth/Source/Private/FIRAdditionalUserInfo_Internal.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRAdditionalUserInfo.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface FIRAdditionalUserInfo () <NSSecureCoding>
+
+/** @fn userInfoWithVerifyAssertionResponse:
+ @brief A convenience factory method for constructing a @c FIRAdditionalUserInfo instance from
+ data returned by the verifyAssertion endpoint.
+ @param verifyAssertionResponse Data returned by the verifyAssertion endpoint.
+ @return A new instance of @c FIRAdditionalUserInfo using data from the verifyAssertion endpoint.
+ */
++ (nullable instancetype)userInfoWithVerifyAssertionResponse:
+ (FIRVerifyAssertionResponse *)verifyAssertionResponse;
+
+/** @fn initWithProviderID:profile:username:
+ @brief Designated initializer.
+ @param providerID The provider identifier.
+ @param profile Dictionary containing the additional IdP specific information.
+ @param username The name of the user.
+ @param isNewUser Indicates whether or not the current user was signed in for the first time.
+ */
+- (nullable instancetype)initWithProviderID:(NSString *)providerID
+ profile:(nullable NSDictionary<NSString *, NSObject *> *)profile
+ username:(nullable NSString *)username
+ isNewUser:(BOOL)isNewUser NS_DESIGNATED_INITIALIZER;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/Private/FIRAuthAPNSToken.h b/Firebase/Auth/Source/Private/FIRAuthAPNSToken.h
new file mode 100644
index 0000000..8efd4e1
--- /dev/null
+++ b/Firebase/Auth/Source/Private/FIRAuthAPNSToken.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "FIRAuthAPNSTokenType.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @class FIRAuthAPNSToken
+ @brief A data structure for an APNs token.
+ */
+@interface FIRAuthAPNSToken : NSObject
+
+/** @property data
+ @brief The APNs token data.
+ */
+@property(nonatomic, strong, readonly) NSData *data;
+
+/** @property type
+ @brief The APNs token type.
+ */
+@property(nonatomic, assign, readonly) FIRAuthAPNSTokenType type;
+
+/** @fn initWithData:type:
+ @brief Initializes the instance.
+ @param data The APNs token data.
+ @param type The APNs token type.
+ @return The initialized instance.
+ */
+- (instancetype)initWithData:(NSData *)data type:(FIRAuthAPNSTokenType)type
+ NS_DESIGNATED_INITIALIZER;
+
+/** @fn init
+ @brief Call @c initWithData:type: to get an instance of this class.
+ */
+- (instancetype)init NS_UNAVAILABLE;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/Private/FIRAuthAPNSTokenManager.h b/Firebase/Auth/Source/Private/FIRAuthAPNSTokenManager.h
new file mode 100644
index 0000000..a2d6f4c
--- /dev/null
+++ b/Firebase/Auth/Source/Private/FIRAuthAPNSTokenManager.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+@class FIRAuthAPNSToken;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @typedef FIRAuthAPNSTokenCallback
+ @brief The type of block to receive an APNs token.
+ @param token The APNs token if one is available.
+ */
+typedef void (^FIRAuthAPNSTokenCallback)(FIRAuthAPNSToken *_Nullable token);
+
+/** @class FIRAuthAPNSTokenManager
+ @brief A class to manage APNs token in memory.
+ */
+@interface FIRAuthAPNSTokenManager : NSObject
+
+/** @property token
+ @brief The APNs token, if one is available.
+ @remarks Setting a token with FIRAuthAPNSTokenTypeUnknown will automatically converts it to
+ a token with the automatically detected type.
+ */
+@property(nonatomic, strong, nullable) FIRAuthAPNSToken *token;
+
+/** @property timeout
+ @brief The timeout for registering for remote notification.
+ @remarks Only tests should access this property.
+ */
+@property(nonatomic, assign) NSTimeInterval timeout;
+
+/** @fn init
+ @brief Call @c initWithApplication: to initialize an instance of this class.
+ */
+- (instancetype)init NS_UNAVAILABLE;
+
+/** @fn initWithApplication:bundle
+ @brief Initializes the instance.
+ @param application The @c UIApplication to request the token from.
+ @return The initialized instance.
+ */
+- (instancetype)initWithApplication:(UIApplication *)application NS_DESIGNATED_INITIALIZER;
+
+/** @fn getTokenWithCallback:
+ @brief Attempts to get the APNs token.
+ @param callback The block to be called either immediately or in future, either when a token
+ becomes available, or when timeout occurs, whichever happens earlier.
+ */
+- (void)getTokenWithCallback:(FIRAuthAPNSTokenCallback)callback;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/Private/FIRAuthAppCredential.h b/Firebase/Auth/Source/Private/FIRAuthAppCredential.h
new file mode 100644
index 0000000..57fa83a
--- /dev/null
+++ b/Firebase/Auth/Source/Private/FIRAuthAppCredential.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @class FIRAuthAppCredential
+ @brief A class represents a credential that proves the identity of the app.
+ */
+@interface FIRAuthAppCredential : NSObject <NSSecureCoding>
+
+/** @property receipt
+ @brief The server acknowledgement of receiving client's claim of identity.
+ */
+@property(nonatomic, strong, readonly) NSString *receipt;
+
+/** @property secret
+ @brief The secret that the client received from server via a trusted channel, if ever.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *secret;
+
+/** @fn initWithReceipt:secret:
+ @brief Initializes the instance.
+ @param receipt The server acknowledgement of receiving client's claim of identity.
+ @param secret The secret that the client received from server via a trusted channel, if ever.
+ @return The initialized instance.
+ */
+- (instancetype)initWithReceipt:(NSString *)receipt secret:(nullable NSString *)secret
+ NS_DESIGNATED_INITIALIZER;
+
+/** @fn init
+ @brief Call @c initWithReceipt:secret: to get an instance of this class.
+ */
+- (instancetype)init NS_UNAVAILABLE;
+
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/Private/FIRAuthAppCredentialManager.h b/Firebase/Auth/Source/Private/FIRAuthAppCredentialManager.h
new file mode 100644
index 0000000..21c1545
--- /dev/null
+++ b/Firebase/Auth/Source/Private/FIRAuthAppCredentialManager.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+@class FIRAuthAppCredential;
+@class FIRAuthKeychain;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @typedef FIRAuthAppCredentialCallback
+ @brief The type of block to receive an app crdential.
+ @param credential The best available app credential at the time.
+ */
+typedef void (^FIRAuthAppCredentialCallback)(FIRAuthAppCredential *credential);
+
+/** @class FIRAuthAppCredentialManager
+ @brief A class to manage app credentials backed by iOS Keychain.
+ */
+@interface FIRAuthAppCredentialManager : NSObject
+
+/** @property credential
+ @brief The full credential (which has a secret) to be used by the app, if one is available.
+ */
+@property(nonatomic, strong, readonly, nullable) FIRAuthAppCredential *credential;
+
+/** @property maximumNumberOfPendingReceipts
+ @brief The maximum (but not necessarily the minimum) number of pending receipts to be kept.
+ @remarks Only tests should access this property.
+ */
+@property(nonatomic, assign, readonly) NSUInteger maximumNumberOfPendingReceipts;
+
+/** @fn init
+ @brief Call @c initWithKeychain: to initialize an instance of this class.
+ */
+- (instancetype)init NS_UNAVAILABLE;
+
+/** @fn initWithKeychain:
+ @brief Initializes the instance.
+ @param keychain The iOS Keychain storage to back up the app credential with.
+ @return The initialized instance.
+ */
+- (instancetype)initWithKeychain:(FIRAuthKeychain *)keychain NS_DESIGNATED_INITIALIZER;
+
+/** @fn didStartVerificationWithReceipt:timeout:callback:
+ @brief Notifies that the app verification process has started.
+ @param receipt The receipt for verification.
+ @param timeout The timeout value for how long the callback is waited to be called.
+ @param callback The block to be called in future either when the verification finishes, or
+ when timeout occurs, whichever happens earlier.
+ */
+- (void)didStartVerificationWithReceipt:(NSString *)receipt
+ timeout:(NSTimeInterval)timeout
+ callback:(FIRAuthAppCredentialCallback)callback;
+
+/** @fn canFinishVerificationWithReceipt:
+ @brief Attempts to finish verification.
+ @param receipt The receipt to match the original receipt obtained when verification started.
+ @param secret The secret to complete the verification.
+ @return Whether or not the receipt matches a pending verification, and finishes verification
+ if it does.
+ */
+- (BOOL)canFinishVerificationWithReceipt:(NSString *)receipt secret:(NSString *)secret;
+
+/** @fn clearCredential
+ @brief Clears the saved credential, to be used in the case that it is rejected by the server.
+ */
+- (void)clearCredential;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/Private/FIRAuthAppDelegateProxy.h b/Firebase/Auth/Source/Private/FIRAuthAppDelegateProxy.h
new file mode 100644
index 0000000..656e4f2
--- /dev/null
+++ b/Firebase/Auth/Source/Private/FIRAuthAppDelegateProxy.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @protocol FIRAuthAppDelegateHandler
+ @brief The protocol to handle app delegate methods.
+ */
+@protocol FIRAuthAppDelegateHandler <NSObject>
+
+/** @fn setAPNSToken:
+ @brief Sets the APNs device token.
+ @param token The APNs device token.
+ */
+- (void)setAPNSToken:(NSData *)token;
+
+/** @fn canHandleNotification:
+ @brief Checks whether the notification can be handled by the receiver, and handles it if so.
+ @param notification The notification in question, which will be consumed if returns @c YES.
+ @return Whether the notification can be (and already has been) handled by the receiver.
+ */
+- (BOOL)canHandleNotification:(nonnull NSDictionary *)notification;
+
+@end
+
+/** @class FIRAuthAppDelegateProxy
+ @brief A manager for swizzling @c UIApplicationDelegate methods.
+ */
+@interface FIRAuthAppDelegateProxy : NSObject
+
+/** @fn initWithApplication
+ @brief Initialize the instance with the given @c UIApplication.
+ @returns An initialized instance, or @c nil if a proxy cannot be established.
+ @remarks This method should only be called from tests if called outside of this class.
+ */
+- (nullable instancetype)initWithApplication:(nullable UIApplication *)application
+ NS_DESIGNATED_INITIALIZER;
+
+/** @fn init
+ @brief Call @c sharedInstance to get an instance of this class.
+ */
+- (instancetype)init NS_UNAVAILABLE;
+
+/** @fn addHandler:
+ @brief Adds a handler for UIApplicationDelegate methods.
+ @param handler The handler to be added.
+ */
+- (void)addHandler:(__weak id<FIRAuthAppDelegateHandler>)handler;
+
+/** @fn sharedInstance
+ @brief Gets the shared instance of this class.
+ @returns The shared instance of this class.
+ */
++ (nullable instancetype)sharedInstance;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/Private/FIRAuthCredential_Internal.h b/Firebase/Auth/Source/Private/FIRAuthCredential_Internal.h
new file mode 100644
index 0000000..e060cda
--- /dev/null
+++ b/Firebase/Auth/Source/Private/FIRAuthCredential_Internal.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRAuthCredential.h"
+
+@class FIRVerifyAssertionRequest;
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface FIRAuthCredential ()
+
+/** @fn initWithProvider:
+ @brief Designated initializer.
+ @remarks This is the designated initializer for internal/friend subclasses.
+ @param provider The provider name.
+ */
+- (nullable instancetype)initWithProvider:(NSString *)provider NS_DESIGNATED_INITIALIZER;
+
+/** @fn prepareVerifyAssertionRequest:
+ @brief Called immediately before a request to the verifyAssertion endpoint is made. Implementers
+ should update the passed request instance with their credentials.
+ @param request The request to be updated with credentials.
+ */
+- (void)prepareVerifyAssertionRequest:(FIRVerifyAssertionRequest *)request;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/Private/FIRAuthDataResult_Internal.h b/Firebase/Auth/Source/Private/FIRAuthDataResult_Internal.h
new file mode 100644
index 0000000..b95edc2
--- /dev/null
+++ b/Firebase/Auth/Source/Private/FIRAuthDataResult_Internal.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRAuthDataResult.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface FIRAuthDataResult () <NSSecureCoding>
+
+/** @fn initWithUser:additionalUserInfo:
+ @brief Designated initializer.
+ @param user The signed in user reference.
+ @param additionalUserInfo The additional user info if available.
+ */
+- (nullable instancetype)initWithUser:(FIRUser *)user
+ additionalUserInfo:(nullable FIRAdditionalUserInfo *)additionalUserInfo
+ NS_DESIGNATED_INITIALIZER;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/Private/FIRAuthDispatcher.h b/Firebase/Auth/Source/Private/FIRAuthDispatcher.h
new file mode 100644
index 0000000..f8ddca5
--- /dev/null
+++ b/Firebase/Auth/Source/Private/FIRAuthDispatcher.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @typedef FIRAuthDispatcherImplBlock
+ @brief The type of block which can be set as the implementation for @c
+ dispatchAfterDelay:queue:callback: .
+
+ @param delay The delay in seconds after which the task will be scheduled to execute.
+ @param queue The dispatch queue on which the task will be submitted.
+ @param task The task (block) to be scheduled for future execution.
+ */
+typedef void(^FIRAuthDispatcherImplBlock)(NSTimeInterval delay,
+ dispatch_queue_t queue,
+ void (^task)(void));
+
+/** @class FIRAuthDispatchAfter
+ @brief A utility class used to facilitate scheduling tasks to be executed in the future.
+ */
+@interface FIRAuthDispatcher : NSObject
+
+/** @property dispatchAfterImplementation
+ @brief Allows custom implementation of dispatchAfterDelay:queue:callback:.
+ @remarks Set to nil to restore default implementation.
+ */
+@property(nonatomic, nullable, copy) FIRAuthDispatcherImplBlock dispatchAfterImplementation;
+
+/** @fn dispatchAfterDelay:queue:callback:
+ @brief Schedules task in the future after a specified delay.
+
+ @param delay The delay in seconds after which the task will be scheduled to execute.
+ @param queue The dispatch queue on which the task will be submitted.
+ @param task The task (block) to be scheduled for future execution.
+ */
+ - (void)dispatchAfterDelay:(NSTimeInterval)delay
+ queue:(dispatch_queue_t)queue
+ task:(void (^)(void))task;
+
+/** @fn sharedInstance
+ @brief Gets the shared instance of this class.
+ @returns The shared instance of this clss
+ */
++ (instancetype)sharedInstance;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/Private/FIRAuthErrorUtils.h b/Firebase/Auth/Source/Private/FIRAuthErrorUtils.h
new file mode 100644
index 0000000..e2ad4aa
--- /dev/null
+++ b/Firebase/Auth/Source/Private/FIRAuthErrorUtils.h
@@ -0,0 +1,418 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+@class FIRPhoneAuthCredential;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @class FIRAuthErrorUtils
+ @brief Utility class used to construct @c NSError instances.
+ */
+@interface FIRAuthErrorUtils : NSObject
+
+/** @fn RPCRequestEncodingErrorWithUnderlyingError
+ @brief Constructs an @c NSError with the @c FIRAuthInternalErrorCodeRPCRequestEncodingError
+ code and a populated @c NSUnderlyingErrorKey in the @c NSError.userInfo dictionary.
+ @param underlyingError The value of the @c NSUnderlyingErrorKey key.
+ @remarks This error is used when an @c FIRAuthRPCRequest.unencodedHTTPRequestBodyWithError:
+ invocation returns an error. The error returned is wrapped in this internal error code.
+ */
++ (NSError *)RPCRequestEncodingErrorWithUnderlyingError:(NSError *)underlyingError;
+
+/** @fn JSONSerializationErrorForUnencodableType
+ @brief Constructs an @c NSError with the @c FIRAuthErrorCodeJSONSerializationError code.
+ @remarks This error is used when an @c NSJSONSerialization.isValidJSONObject: check fails, not
+ for when an error is returned from @c NSJSONSerialization.dataWithJSONObject:options:error:.
+ */
++ (NSError *)JSONSerializationErrorForUnencodableType;
+
+/** @fn JSONSerializationErrorWithUnderlyingError:
+ @brief Constructs an @c NSError with the @c FIRAuthErrorCodeJSONSerializationError code, and the
+ @c underlyingError as the @c NSUnderlyingErrorKey value in the @c NSError.userInfo
+ dictionary.
+ @param underlyingError The value of the @c NSUnderlyingErrorKey key.
+ @remarks This error is used when an invocation of
+ @c NSJSONSerialization.dataWithJSONObject:options:error: returns an error.
+ */
++ (NSError *)JSONSerializationErrorWithUnderlyingError:(NSError *)underlyingError;
+
+/** @fn networkErrorWithUnderlyingError:
+ @brief Constructs an @c NSError with the @c FIRAuthErrorCodeNetworkError code, and the
+ @c underlyingError as the @c NSUnderlyingErrorKey value in the @c NSError.userInfo
+ dictionary.
+ @param underlyingError The value of the @c NSUnderlyingErrorKey key. Should be the error from
+ GTM.
+ @remarks This error is used when a network request results in an error, and no body data was
+ returned.
+ */
++ (NSError *)networkErrorWithUnderlyingError:(NSError *)underlyingError;
+
+/** @fn unexpectedErrorResponseWithUnderlyingError:
+ @brief Constructs an @c NSError with the @c FIRAuthErrorCodeNetworkError code, and the
+ @c underlyingError as the @c NSUnderlyingErrorKey value.
+ @param data The value of the @c FIRAuthErrorUserInfoDataKey key in the @c NSError.userInfo
+ dictionary.
+ @param underlyingError The value of the @c NSUnderlyingErrorKey key in the @c NSError.userInfo
+ dictionary.
+ @remarks This error is used when a network request results in an error, and unserializable body
+ data was returned.
+ */
++ (NSError *)unexpectedErrorResponseWithData:(NSData *)data
+ underlyingError:(NSError *)underlyingError;
+
+/** @fn unexpectedErrorResponseWithDeserializedResponse:
+ @brief Constructs an @c NSError with the @c FIRAuthInternalErrorCodeUnexpectedErrorResponse
+ code, and a populated @c FIRAuthErrorUserInfoDeserializedResponseKey key in the
+ @c NSError.userInfo dictionary.
+ @param deserializedResponse The value of the @c FIRAuthErrorUserInfoDeserializedResponseKey key.
+ @remarks This error is used when a network request results in an error, and the body data was
+ deserializable as JSON, but couldn't be decoded as an error.
+ */
++ (NSError *)unexpectedErrorResponseWithDeserializedResponse:(id)deserializedResponse;
+
+/** @fn unexpectedResponseWithData:underlyingError:
+ @brief Constructs an @c NSError with the @c FIRAuthInternalErrorCodeUnexpectedResponse
+ code, and a populated @c FIRAuthErrorUserInfoDataKey key in the @c NSError.userInfo
+ dictionary.
+ @param data The value of the @c FIRAuthErrorUserInfoDataKey key in the @c NSError.userInfo
+ dictionary.
+ @param underlyingError The value of the @c NSUnderlyingErrorKey key in the @c NSError.userInfo
+ dictionary.
+ @remarks This error is used when a network request is apparently successful, but the body data
+ couldn't be deserialized as JSON.
+ */
++ (NSError *)unexpectedResponseWithData:(NSData *)data
+ underlyingError:(NSError *)underlyingError;;
+
+/** @fn unexpectedResponseWithDeserializedResponse:
+ @brief Constructs an @c NSError with the @c FIRAuthInternalErrorCodeUnexpectedResponse
+ code, and a populated @c FIRAuthErrorUserInfoDeserializedResponseKey key in the
+ @c NSError.userInfo dictionary.
+ @param deserializedResponse The value of the @c FIRAuthErrorUserInfoDeserializedResponseKey key.
+ @remarks This error is used when a network request is apparently successful, the body data was
+ successfully deserialized as JSON, but the JSON wasn't a dictionary.
+ */
++ (NSError *)unexpectedResponseWithDeserializedResponse:(id)deserializedResponse;
+
+/** @fn unexpectedResponseWithDeserializedResponse:underlyingError:
+ @brief Constructs an @c NSError with the @c FIRAuthInternalErrorCodeUnexpectedResponse
+ code, and populated @c FIRAuthErrorUserInfoDeserializedResponseKey and
+ @c NSUnderlyingErrorKey keys in the @c NSError.userInfo dictionary.
+ @param deserializedResponse The value of the @c FIRAuthErrorUserInfoDeserializedResponseKey key.
+ @param underlyingError The value of the @c NSUnderlyingErrorKey key.
+ @remarks This error is used when a network request was apparently successful, the body data was
+ successfully deserialized as JSON, but the data type of the response was unexpected.
+ */
++ (NSError *)unexpectedResponseWithDeserializedResponse:(nullable id)deserializedResponse
+ underlyingError:(NSError *)underlyingError;
+
+/** @fn RPCResponseDecodingErrorWithDeserializedResponse:underlyingError:
+ @brief Constructs an @c NSError with the @c FIRAuthInternalErrorCodeRPCResponseDecodingError
+ code, and populated @c FIRAuthErrorUserInfoDeserializedResponseKey and
+ @c NSUnderlyingErrorKey keys in the @c NSError.userInfo dictionary.
+ @param deserializedResponse The value of the @c FIRAuthErrorUserInfoDeserializedResponseKey key.
+ @param underlyingError The value of the @c NSUnderlyingErrorKey key.
+ @remarks This error is used when an invocation of @c FIRAuthRPCResponse.setWithDictionary:error:
+ resulted in an error.
+ */
++ (NSError *)RPCResponseDecodingErrorWithDeserializedResponse:(id)deserializedResponse
+ underlyingError:(NSError *)underlyingError;
+
+/** @fn emailAlreadyInUseErrorWithEmail:
+ @brief Constructs an @c NSError with the @c FIRAuthErrorCodeEmailExists code.
+ @param email The email address that is already in use.
+ @return The NSError instance associated with the given FIRAuthError.
+ */
++ (NSError *)emailAlreadyInUseErrorWithEmail:(nullable NSString *)email;
+
+/** @fn userDisabledErrorWithMessageWithMessage:
+ @brief Constructs an @c NSError with the @c FIRAuthErrorCodeUserDisabled code.
+ @param message Error message from the backend, if any.
+ @return The NSError instance associated with the given FIRAuthError.
+ */
++ (NSError *)userDisabledErrorWithMessage:(nullable NSString *)message;
+
+/** @fn wrongPasswordErrorWithMessage:
+ @brief Constructs an @c NSError with the @c FIRAuthErrorCodeWrongPassword code.
+ @param message Error message from the backend, if any.
+ @return The NSError instance associated with the given FIRAuthError.
+ */
++ (NSError *)wrongPasswordErrorWithMessage:(nullable NSString *)message;
+
+/** @fn tooManyRequestsErrorWithMessage:
+ @brief Constructs an @c NSError with the @c FIRAuthErrorCodeTooManyRequests Code.
+ @param message Error message from the backend, if any.
+ @return The NSError instance associated with the given FIRAuthError.
+ */
++ (NSError *)tooManyRequestsErrorWithMessage:(nullable NSString *)message;
+
+/** @fn invalidCustomTokenErrorWithMessage:
+ @brief Constructs an @c NSError with the @c FIRAuthErrorCodeInvalidCustomToken code.
+ @param message Error message from the backend, if any.
+ @return The NSError instance associated with the given FIRAuthError.
+ */
++ (NSError *)invalidCustomTokenErrorWithMessage:(nullable NSString *)message;
+
+/** @fn customTokenMistmatchErrorWithMessage:
+ @brief Constructs an @c NSError with the @c FIRAuthErrorCodeCustomTokenMismatch code.
+ @param message Error message from the backend, if any.
+ @return The NSError instance associated with the given FIRAuthError.
+ */
++ (NSError *)customTokenMistmatchErrorWithMessage:(nullable NSString *)message;
+
+/** @fn invalidCredentialErrorWithMessage:
+ @brief Constructs an @c NSError with the @c FIRAuthErrorCodeInvalidCredential code.
+ @param message Error message from the backend, if any.
+ @return The NSError instance associated with the given FIRAuthError.
+ */
++ (NSError *)invalidCredentialErrorWithMessage:(nullable NSString *)message;
+
+/** @fn requiresRecentLoginError
+ @brief Constructs an @c NSError with the @c FIRAuthErrorCodeRequiresRecentLogin code.
+ @param message Error message from the backend, if any.
+ @return The NSError instance associated with the given FIRAuthError.
+ */
++ (NSError *)requiresRecentLoginErrorWithMessage:(nullable NSString *)message;
+
+/** @fn invalidUserTokenErrorWithMessage:
+ @brief Constructs an @c NSError with the @c FIRAuthErrorCodeInvalidUserToken code.
+ @param message Error message from the backend, if any.
+ @return The NSError instance associated with the given FIRAuthError.
+ */
++ (NSError *)invalidUserTokenErrorWithMessage:(nullable NSString *)message;
+
+/** @fn invalidEmailErrorWithMessage:
+ @brief Constructs an @c NSError with the @c FIRAuthErrorCodeInvalidEmail code.
+ @param message Error message from the backend, if any.
+ @return The NSError instance associated with the given FIRAuthError.
+ */
++ (NSError *)invalidEmailErrorWithMessage:(nullable NSString *)message;
+
+/** @fn accountExistsWithDifferentCredentialErrorWithEmail:
+ @brief Constructs an @c NSError with the @c FIRAuthErrorAccountExistsWithDifferentCredential
+ code.
+ @param Email The email address that is already associated with an existing account
+ @return The NSError instance associated with the given FIRAuthError.
+ */
++ (NSError *)accountExistsWithDifferentCredentialErrorWithEmail:(nullable NSString *)Email;
+
+/** @fn providerAlreadyLinkedErrorWithMessage:
+ @brief Constructs an @c NSError with the @c FIRAuthErrorCodeProviderAlreadyLinked code.
+ @return The NSError instance associated with the given FIRAuthError.
+ */
++ (NSError *)providerAlreadyLinkedError;
+
+/** @fn noSuchProviderError
+ @brief Constructs an @c NSError with the @c FIRAuthErrorCodeNoSuchProvider code.
+ @return The NSError instance associated with the given FIRAuthError.
+ */
++ (NSError *)noSuchProviderError;
+
+/** @fn userTokenExpiredErrorWithMessage:
+ @brief Constructs an @c NSError with the @c FIRAuthErrorCodeUserTokenExpired code.
+ @param message Error message from the backend, if any.
+ @return The NSError instance associated with the given FIRAuthError.
+ */
++ (NSError *)userTokenExpiredErrorWithMessage:(nullable NSString *)message;
+
+/** @fn userNotFoundErrorWithMessage:
+ @brief Constructs an @c NSError with the @c FIRAuthErrorCodeUserNotFound code.
+ @param message Error message from the backend, if any.
+ @return The NSError instance associated with the given FIRAuthError.
+ */
++ (NSError *)userNotFoundErrorWithMessage:(nullable NSString *)message;
+
+/** @fn invalidLocalAPIKeyErrorWithMessage:
+ @brief Constructs an @c NSError with the @c FIRAuthErrorCodeInvalidAPIKey code.
+ @return The NSError instance associated with the given FIRAuthError.
+ */
++ (NSError *)invalidAPIKeyError;
+
+/** @fn userMismatchError
+ @brief Constructs an @c NSError with the @c FIRAuthErrorCodeUserMismatch code.
+ @return The NSError instance associated with the given FIRAuthError.
+ */
++ (NSError *)userMismatchError;
+
+/** @fn credentialAlreadyInUseErrorWithMessage:
+ @brief Constructs an @c NSError with the @c FIRAuthErrorCodeCredentialAlreadyInUse code.
+ @param message Error message from the backend, if any.
+ @param credential Auth credential to be added to the Error User Info dictionary.
+ @return The NSError instance associated with the given FIRAuthError.
+ */
++ (NSError *)credentialAlreadyInUseErrorWithMessage:(nullable NSString *)message
+ credential:(nullable FIRPhoneAuthCredential *)credential;
+
+/** @fn operationNotAllowedErrorWithMessage:
+ @brief Constructs an @c NSError with the @c FIRAuthErrorCodeOperationNotAllowed code.
+ @param message Error message from the backend, if any.
+ @return The NSError instance associated with the given FIRAuthError.
+ */
++ (NSError *)operationNotAllowedErrorWithMessage:(nullable NSString *)message;
+
+/** @fn weakPasswordErrorWithServerResponseReason:
+ @brief Constructs an @c NSError with the @c FIRAuthErrorCodeWeakPassword code.
+ @param serverResponseReason A more detailed explanation string from server response.
+ @return The NSError instance associated with the given FIRAuthError.
+ */
++ (NSError *)weakPasswordErrorWithServerResponseReason:(NSString *)serverResponseReason;
+
+/** @fn appNotAuthorizedError
+ @brief Constructs an @c NSError with the @c FIRAuthErrorCodeAppNotAuthorized code.
+ @return The NSError instance associated with the given FIRAuthError.
+ */
++ (NSError *)appNotAuthorizedError;
+
+/** @fn expiredActionCodeErrorWithMessage:
+ @brief Constructs an @c NSError with the @c FIRAuthErrorCodeExpiredActionCode code.
+ @param message Error message from the backend, if any.
+ @return The NSError instance associated with the given FIRAuthError.
+ */
++ (NSError *)expiredActionCodeErrorWithMessage:(nullable NSString *)message;
+
+/** @fn invalidActionCodeErrorWithMessage:
+ @brief Constructs an @c NSError with the @c FIRAuthErrorCodeInvalidActionCode code.
+ @param message Error message from the backend, if any.
+ @return The NSError instance associated with the given FIRAuthError.
+ */
++ (NSError *)invalidActionCodeErrorWithMessage:(nullable NSString *)message;
+
+/** @fn invalidMessagePayloadError:
+ @brief Constructs an @c NSError with the @c FIRAuthErrorCodeInvalidMessagePayload code.
+ @param message Error message from the backend, if any.
+ @return The NSError instance associated with the given FIRAuthError.
+ */
++ (NSError *)invalidMessagePayloadErrorWithMessage:(nullable NSString *)message;
+
+/** @fn invalidSenderErrorWithMessage:
+ @brief Constructs an @c NSError with the @c FIRAuthErrorCodeInvalidSender code.
+ @param message Error message from the backend, if any.
+ @return The NSError instance associated with the given FIRAuthError.
+ */
++ (NSError *)invalidSenderErrorWithMessage:(nullable NSString *)message;
+
+/** @fn invalidRecipientEmailError:
+ @brief Constructs an @c NSError with the @c FIRAuthErrorCodeInvalidRecipientEmail code.
+ @param message Error message from the backend, if any.
+ @return The NSError instance associated with the given FIRAuthError.
+ */
++ (NSError *)invalidRecipientEmailErrorWithMessage:(nullable NSString *)message;
+
+/** @fn missingPhoneNumberErrorWithMessage:
+ @brief Constructs an @c NSError with the @c FIRAuthErrorCodeMissingPhoneNumber code.
+ @param message Error message from the backend, if any.
+ @return The NSError instance associated with the given FIRAuthError.
+ */
++ (NSError *)missingPhoneNumberErrorWithMessage:(nullable NSString *)message;
+
+/** @fn invalidPhoneNumberErrorWithMessage:
+ @brief Constructs an @c NSError with the @c FIRAuthErrorCodeInvalidPhoneNumber code.
+ @param message Error message from the backend, if any.
+ @return The NSError instance associated with the given FIRAuthError.
+ */
++ (NSError *)invalidPhoneNumberErrorWithMessage:(nullable NSString *)message;
+
+/** @fn missingVerificationCodeErrorWithMessage:
+ @brief Constructs an @c NSError with the @c FIRAuthErrorCodeMissingVerificationCode code.
+ @param message Error message from the backend, if any.
+ @return The NSError instance associated with the given FIRAuthError.
+ */
++ (NSError *)missingVerificationCodeErrorWithMessage:(nullable NSString *)message;
+
+/** @fn invalidVerificationCodeErrorWithMessage:
+ @brief Constructs an @c NSError with the @c FIRAuthErrorCodeInvalidVerificationCode code.
+ @param message Error message from the backend, if any.
+ @return The NSError instance associated with the given FIRAuthError.
+ */
++ (NSError *)invalidVerificationCodeErrorWithMessage:(nullable NSString *)message;
+
+/** @fn missingVerificationIDErrorWithMessage:
+ @brief Constructs an @c NSError with the @c FIRAuthErrorCodeMissingVerificationID code.
+ @param message Error message from the backend, if any.
+ @return The NSError instance associated with the given FIRAuthError.
+ */
++ (NSError *)missingVerificationIDErrorWithMessage:(nullable NSString *)message;
+
+/** @fn invalidVerificationIDErrorWithMessage:
+ @brief Constructs an @c NSError with the @c FIRAuthErrorCodeInvalidVerificationID code.
+ @param message Error message from the backend, if any.
+ @return The NSError instance associated with the given FIRAuthError.
+ */
++ (NSError *)invalidVerificationIDErrorWithMessage:(nullable NSString *)message;
+
+/** @fn sessionExpiredErrorWithMessage:
+ @brief Constructs an @c NSError with the @c FIRAuthErrorCodeSessionExpired code.
+ @param message Error message from the backend, if any.
+ @return The NSError instance associated with the given FIRAuthError.
+ */
++ (NSError *)sessionExpiredErrorWithMessage:(nullable NSString *)message;
+
+/** @fn missingAppCredentialWithMessage:
+ @brief Constructs an @c NSError with the @c FIRAuthErrorMissingCredential code.
+ @param message Error message from the backend, if any.
+ @return The NSError instance associated with the given FIRAuthError.
+ */
++ (NSError *)missingAppCredentialWithMessage:(nullable NSString *)message;
+
+/** @fn invalidAppCredentialWithMessage:
+ @brief Constructs an @c NSError with the @c FIRAuthErrorInvalidCredential code.
+ @param message Error message from the backend, if any.
+ @return The NSError instance associated with the given FIRAuthError.
+ */
++ (NSError *)invalidAppCredentialWithMessage:(nullable NSString *)message;
+
+/** @fn quotaExceededErrorWithMessage:
+ @brief Constructs an @c NSError with the @c FIRAuthErrorCodeQuotaExceeded code.
+ @param message Error message from the backend, if any.
+ @return The NSError instance associated with the given FIRAuthError.
+ */
++ (NSError *)quotaExceededErrorWithMessage:(nullable NSString *)message;
+
+/** @fn missingAppTokenError
+ @brief Constructs an @c NSError with the @c FIRAuthErrorCodeMissingAppToken code.
+ @return The NSError instance associated with the given FIRAuthError.
+ */
++ (NSError *)missingAppTokenError;
+
+/** @fn notificationNotForwardedError
+ @brief Constructs an @c NSError with the @c FIRAuthErrorCodeNotificationNotForwarded code.
+ @return The NSError instance associated with the given FIRAuthError.
+ */
++ (NSError *)notificationNotForwardedError;
+
+/** @fn appNotVerifiedErrorWithMessage:
+ @brief Constructs an @c NSError with the @c FIRAuthErrorCodeAppNotVerified code.
+ @param message Error message from the backend, if any.
+ @return The NSError instance associated with the given FIRAuthError.
+ */
++ (NSError *)appNotVerifiedErrorWithMessage:(nullable NSString *)message;
+
+/** @fn keychainErrorWithFunction:status:
+ @brief Constructs an @c NSError with the @c FIRAuthErrorCodeKeychainError code.
+ @param keychainFunction The keychain function which was invoked and yielded an unexpected
+ response. The @c NSLocalizedFailureReasonErrorKey field in the @c NSError.userInfo
+ dictionary will contain a string partially comprised of this value.
+ @param status The response status from the invoked keychain function. The
+ @c NSLocalizedFailureReasonErrorKey field in the @c NSError.userInfo dictionary will contain
+ a string partially comprised of this value.
+ */
++ (NSError *)keychainErrorWithFunction:(NSString *)keychainFunction status:(OSStatus)status;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/Private/FIRAuthGlobalWorkQueue.h b/Firebase/Auth/Source/Private/FIRAuthGlobalWorkQueue.h
new file mode 100644
index 0000000..0950ff4
--- /dev/null
+++ b/Firebase/Auth/Source/Private/FIRAuthGlobalWorkQueue.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @fn FIRAuthGlobalWorkQueue
+ @brief Retrieves the global serial work queue for Firebase Auth.
+ @return The global serial dispatch queue.
+ @remarks To ensure thread safety, all auth code must be executed in either this global work
+ queue, or a serial queue that has its target queue set to this work queue. All public method
+ implementations that may involve contested code shall dispatch to this work queue as the
+ first thing they do.
+ */
+extern dispatch_queue_t FIRAuthGlobalWorkQueue();
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/Private/FIRAuthInternalErrors.h b/Firebase/Auth/Source/Private/FIRAuthInternalErrors.h
new file mode 100644
index 0000000..7eebbde
--- /dev/null
+++ b/Firebase/Auth/Source/Private/FIRAuthInternalErrors.h
@@ -0,0 +1,365 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "FIRAuthErrors.h"
+
+/** @var FIRAuthPublicErrorCodeFlag
+ @brief Bitmask value indicating the error represents a public error code when this bit is
+ zeroed. Error codes which don't contain this flag will be wrapped in an @c NSError whose
+ code is @c FIRAuthErrorCodeInternalError.
+ */
+static const NSInteger FIRAuthPublicErrorCodeFlag = 1 << 20;
+
+/** @var FIRAuthInternalErrorDomain
+ @brief The Firebase Auth error domain for internal errors.
+ */
+extern NSString *const FIRAuthInternalErrorDomain;
+
+/** @var FIRAuthErrorUserInfoDeserializedResponseKey
+ @brief Errors with the code @c FIRAuthErrorCodeUnexpectedResponseError,
+ @c FIRAuthErrorCodeUnexpectedErrorResponseError, and
+ @c FIRAuthInternalErrorCodeRPCResponseDecodingError may contain an @c NSError.userInfo
+ dictionary which contains this key. The value associated with this key is an object of
+ unspecified contents containing the deserialized server response.
+ */
+extern NSString *const FIRAuthErrorUserInfoDeserializedResponseKey;
+
+/** @var FIRAuthErrorUserInfoDataKey
+ @brief Errors with the code @c FIRAuthErrorCodeUnexpectedResponseError or
+ @c FIRAuthErrorCodeUnexpectedErrorResponseError may contain an @c NSError.userInfo
+ dictionary which contains this key. The value associated with this key is an @c NSString
+ which represents the response from a server to an RPC which could not be deserialized.
+ */
+extern NSString *const FIRAuthErrorUserInfoDataKey;
+
+
+/** @var FIRAuthInternalErrorCode
+ @brief Error codes used internally by Firebase Auth.
+ @remarks All errors are generated using an internal error code. These errors are automatically
+ converted to the appropriate public version of the @c NSError by the methods in
+ @c FIRAuthErrorUtils
+ */
+typedef NS_ENUM(NSInteger, FIRAuthInternalErrorCode) {
+ /** @var FIRAuthInternalErrorCodeNetworkError
+ @brief Indicates a network error occurred (such as a timeout, interrupted connection, or
+ unreachable host.)
+ @remarks These types of errors are often recoverable with a retry.
+
+ See the @c NSUnderlyingError value in the @c NSError.userInfo dictionary for details about
+ the network error which occurred.
+ */
+ FIRAuthInternalErrorCodeNetworkError = FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeNetworkError,
+
+ /** @var FIRAuthInternalErrorCodeEmailAlreadyInUse
+ @brief The email used to attempt a sign-up already exists.
+ */
+ FIRAuthInternalErrorCodeEmailAlreadyInUse =
+ FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeEmailAlreadyInUse,
+
+ /** @var FIRAuthInternalErrorCodeUserDisabled
+ @brief Indicates the user's account is disabled on the server side.
+ */
+ FIRAuthInternalErrorCodeUserDisabled = FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeUserDisabled,
+
+ /** @var FIRAuthInternalErrorCodeWrongPassword
+ @brief Indicates the user attempted sign in with a wrong password
+ */
+ FIRAuthInternalErrorCodeWrongPassword =
+ FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeWrongPassword,
+
+ /** @var FIRAuthInternalErrorCodeKeychainError
+ @brief Indicates an error occurred accessing the keychain.
+ @remarks The @c NSLocalizedFailureReasonErrorKey field in the @c NSError.userInfo dictionary
+ will contain more information about the error encountered.
+ */
+ FIRAuthInternalErrorCodeKeychainError =
+ FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeKeychainError,
+
+ /** @var FIRAuthInternalErrorCodeInternalError
+ @brief An internal error occurred.
+ @remarks This value is here for consistency. It's also used to make the implementation of
+ wrapping internal errors simpler.
+ */
+ FIRAuthInternalErrorCodeInternalError =
+ FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeInternalError,
+
+ /** @var FIRAuthInternalErrorCodeTooManyRequests
+ @brief Indicates that too many requests were made to a server method.
+ */
+ FIRAuthInternalErrorCodeTooManyRequests =
+ FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeTooManyRequests,
+
+ /** @var FIRAuthInternalErrorCodeInvalidCustomToken
+ @brief Indicates a validation error with the custom token.
+ */
+ FIRAuthInternalErrorCodeInvalidCustomToken =
+ FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeInvalidCustomToken,
+
+ /** @var FIRAuthInternalErrorCodeCredentialMismatch
+ @brief Indicates the service account and the API key belong to different projects.
+ */
+ FIRAuthInternalErrorCodeCustomTokenMismatch =
+ FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeCustomTokenMismatch,
+
+ /** @var FIRAuthInternalErrorCodeInvalidCredential
+ @brief Indicates the IDP token or requestUri is invalid.
+ */
+ FIRAuthInternalErrorCodeInvalidCredential =
+ FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeInvalidCredential,
+
+ /** @var FIRAuthInternalErrorCodeRequiresRecentLogin
+ @brief Indicates the user has attemped to change email or password more than 5 minutes after
+ signing in.
+ */
+ FIRAuthInternalErrorCodeRequiresRecentLogin =
+ FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeRequiresRecentLogin,
+
+ /** @var FIRAuthInternalErrorCodeInvalidUserToken
+ @brief Indicates user's saved auth credential is invalid, the user needs to sign in again.
+ */
+ FIRAuthInternalErrorCodeInvalidUserToken =
+ FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeInvalidUserToken,
+
+ /** @var FIRAuthInternalErrorCodeInvalidEmail
+ @brief Indicates the email identifier is invalid.
+ */
+ FIRAuthInternalErrorCodeInvalidEmail =
+ FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeInvalidEmail,
+
+ /** @var FIRAuthInternalErrorCodeAccountExistsWithDifferentCredential
+ @brief Indicates account linking is needed.
+ */
+ FIRAuthInternalErrorCodeAccountExistsWithDifferentCredential =
+ FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeAccountExistsWithDifferentCredential,
+
+ /** @var FIRAuthInternalErrorCodeProviderAlreadyLinked
+ @brief Indicates an attempt to link a provider to which we are already linked.
+ */
+ FIRAuthInternalErrorCodeProviderAlreadyLinked =
+ FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeProviderAlreadyLinked,
+
+ /** @var FIRAuthInternalErrorCodeNoSuchProvider
+ @brief Indicates an attempt to unlink a provider that is not is not linked.
+ */
+ FIRAuthInternalErrorCodeNoSuchProvider =
+ FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeNoSuchProvider,
+
+ /** @var FIRAuthInternalErrorCodeUserTokenExpired
+ @brief Indicates the token issue time is older than account's valid_since time.
+ */
+ FIRAuthInternalErrorCodeUserTokenExpired =
+ FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeUserTokenExpired,
+
+ /** @var FIRAuthInternalErrorCodeUserNotFound
+ @brief Indicates the user account was been found.
+ */
+ FIRAuthInternalErrorCodeUserNotFound =
+ FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeUserNotFound,
+
+ /** @var FIRAuthInternalErrorCodeInvalidAPIKey
+ @brief Indicates an invalid API Key was supplied in the request.
+ */
+ FIRAuthInternalErrorCodeInvalidAPIKey =
+ FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeInvalidAPIKey,
+
+ /** @var FIRAuthInternalErrorCodeOperationNotAllowed
+ @brief Indicates that admin disabled sign-in with the specified IDP.
+ */
+ FIRAuthInternalErrorCodeOperationNotAllowed =
+ FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeOperationNotAllowed,
+
+ /** @var FIRAuthInternalErrorCodeUserMismatch
+ @brief Indicates that user attempted to reauthenticate with a user other than the current
+ user.
+ */
+ FIRAuthInternalErrorCodeUserMismatch =
+ FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeUserMismatch,
+
+ /** @var FIRAuthInternalErrorCodeCredentialAlreadyInUse
+ @brief Indicates an attempt to link with a credential that has already been linked with a
+ different Firebase account.
+ */
+ FIRAuthInternalErrorCodeCredentialAlreadyInUse =
+ FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeCredentialAlreadyInUse,
+
+ /** @var FIRAuthInternalErrorCodeWeakPassword
+ @brief Indicates an attempt to set a password that is considered too weak.
+ */
+ FIRAuthInternalErrorCodeWeakPassword =
+ FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeWeakPassword,
+
+ /** @var FIRAuthInternalErrorCodeAppNotAuthorized
+ @brief Indicates the App is not authorized to use Firebase Authentication with the
+ provided API Key.
+ */
+ FIRAuthInternalErrorCodeAppNotAuthorized =
+ FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeAppNotAuthorized,
+
+ /** @var FIRAuthInternalErrorCodeExpiredActionCode
+ @brief Indicates the OOB code is expired.
+ */
+ FIRAuthInternalErrorCodeExpiredActionCode =
+ FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeExpiredActionCode,
+
+ /** @var FIRAuthInternalErrorCodeInvalidActionCode
+ @brief Indicates the OOB code is invalid.
+ */
+ FIRAuthInternalErrorCodeInvalidActionCode =
+ FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeInvalidActionCode,
+
+ /** Indicates that there are invalid parameters in the payload during a "send password reset email
+ * " attempt.
+ */
+ FIRAuthInternalErrorCodeInvalidMessagePayload =
+ FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeInvalidMessagePayload,
+
+ /** Indicates that the sender email is invalid during a "send password reset email" attempt.
+ */
+ FIRAuthInternalErrorCodeInvalidSender =
+ FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeInvalidSender,
+
+ /** Indicates that the recipient email is invalid.
+ */
+ FIRAuthInternalErrorCodeInvalidRecipientEmail =
+ FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeInvalidRecipientEmail,
+
+ /** Indicates that a phone number was not provided in a call to @c verifyPhoneNumber:completion:.
+ */
+ FIRAuthInternalErrorCodeMissingPhoneNumber =
+ FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeMissingPhoneNumber,
+
+ /** Indicates that an invalid phone number was provided in a call to @c
+ verifyPhoneNumber:completion:.
+ */
+ FIRAuthInternalErrorCodeInvalidPhoneNumber =
+ FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeInvalidPhoneNumber,
+
+ /** Indicates that the phone auth credential was created with an empty verification code.
+ */
+ FIRAuthInternalErrorCodeMissingVerificationCode =
+ FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeMissingVerificationCode,
+
+ /** Indicates that an invalid verification code was used in the verifyPhoneNumber request.
+ */
+ FIRAuthInternalErrorCodeInvalidVerificationCode =
+ FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeInvalidVerificationCode,
+
+ /** Indicates that the phone auth credential was created with an empty verification ID.
+ */
+ FIRAuthInternalErrorCodeMissingVerificationID =
+ FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeMissingVerificationID,
+
+ /** Indicates that the APNS device token is missing in the verifyClient request.
+ */
+ FIRAuthInternalErrorCodeMissingAppCredential =
+ FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeMissingAppCredential,
+
+ /** Indicates that an invalid APNS device token was used in the verifyClient request.
+ */
+ FIRAuthInternalErrorCodeInvalidAppCredential =
+ FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeInvalidAppCredential,
+
+ /** Indicates that an invalid verification ID was used in the verifyPhoneNumber request.
+ */
+ FIRAuthInternalErrorCodeInvalidVerificationID =
+ FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeInvalidVerificationID,
+
+ /** Indicates that the quota of SMS messages for a given project has been exceeded.
+ */
+ FIRAuthInternalErrorCodeQuotaExceeded =
+ FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeQuotaExceeded,
+
+ // The enum values between 17046 and 17051 are reserved and should NOT be used for new error
+ // codes.
+
+ /** Indicates that the SMS code has expired
+ */
+ FIRAuthInternalErrorCodeSessionExpired =
+ FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeSessionExpired,
+
+ FIRAuthInternalErrorCodeMissingAppToken =
+ FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeMissingAppToken,
+
+ FIRAuthInternalErrorCodeNotificationNotForwarded =
+ FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeNotificationNotForwarded,
+
+ FIRAuthInternalErrorCodeAppNotVerified =
+ FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeAppNotVerified,
+
+ /** @var FIRAuthInternalErrorCodeRPCRequestEncodingError
+ @brief Indicates an error encoding the RPC request.
+ @remarks This is typically due to some sort of unexpected input value.
+
+ See the @c NSUnderlyingError value in the @c NSError.userInfo dictionary for details.
+ */
+ FIRAuthInternalErrorCodeRPCRequestEncodingError = 1,
+
+ /** @var FIRAuthInternalErrorCodeJSONSerializationError
+ @brief Indicates an error serializing an RPC request.
+ @remarks This is typically due to some sort of unexpected input value.
+
+ If an @c NSJSONSerialization.isValidJSONObject: check fails, the error will contain no
+ @c NSUnderlyingError key in the @c NSError.userInfo dictionary. If an error was
+ encountered calling @c NSJSONSerialization.dataWithJSONObject:options:error:, the
+ resulting error will be associated with the @c NSUnderlyingError key in the
+ @c NSError.userInfo dictionary.
+ */
+ FIRAuthInternalErrorCodeJSONSerializationError = 2,
+
+ /** @var FIRAuthInternalErrorCodeUnexpectedErrorResponse
+ @brief Indicates an HTTP error occurred and the data returned either couldn't be deserialized
+ or couldn't be decoded.
+ @remarks See the @c NSUnderlyingError value in the @c NSError.userInfo dictionary for details
+ about the HTTP error which occurred.
+
+ If the response could be deserialized as JSON then the @c NSError.userInfo dictionary will
+ contain a value for the key @c FIRAuthErrorUserInfoDeserializedResponseKey which is the
+ deserialized response value.
+
+ If the response could not be deserialized as JSON then the @c NSError.userInfo dictionary
+ will contain values for the @c NSUnderlyingErrorKey and @c FIRAuthErrorUserInfoDataKey
+ keys.
+ */
+ FIRAuthInternalErrorCodeUnexpectedErrorResponse = 3,
+
+ /** @var FIRAuthInternalErrorCodeUnexpectedResponse
+ @brief Indicates the HTTP response indicated the request was a successes, but the response
+ contains something other than a JSON-encoded dictionary, or the data type of the response
+ indicated it is different from the type of response we expected.
+ @remarks See the @c NSUnderlyingError value in the @c NSError.userInfo dictionary.
+ If this key is present in the dictionary, it may contain an error from
+ @c NSJSONSerialization error (indicating the response received was of the wrong data
+ type).
+
+ See the @c FIRAuthErrorUserInfoDeserializedResponseKey value in the @c NSError.userInfo
+ dictionary. If the response could be deserialized, it's deserialized representation will
+ be associated with this key. If the @c NSUnderlyingError value in the @c NSError.userInfo
+ dictionary is @c nil, this indicates the JSON didn't represent a dictionary.
+ */
+ FIRAuthInternalErrorCodeUnexpectedResponse = 4,
+
+ /** @var FIRAuthInternalErrorCodeRPCResponseDecodingError
+ @brief Indicates an error decoding the RPC response.
+ This is typically due to some sort of unexpected response value from the server.
+ @remarks See the @c NSUnderlyingError value in the @c NSError.userInfo dictionary for details.
+
+ See the @c FIRErrorUserInfoDecodedResponseKey value in the @c NSError.userInfo dictionary.
+ The deserialized representation of the response will be associated with this key.
+ */
+ FIRAuthInternalErrorCodeRPCResponseDecodingError = 5,
+};
diff --git a/Firebase/Auth/Source/Private/FIRAuthKeychain.h b/Firebase/Auth/Source/Private/FIRAuthKeychain.h
new file mode 100644
index 0000000..c52e26a
--- /dev/null
+++ b/Firebase/Auth/Source/Private/FIRAuthKeychain.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ @brief The protocol for permanant data storage.
+ */
+@protocol FIRAuthStorage <NSObject>
+
+/** @fn initWithService:
+ @brief Initialize a @c FIRAuthStorage instance.
+ @param service The name of the storage service to use.
+ @return An initialized @c FIRAuthStorage instance for the specified service.
+ */
+- (id<FIRAuthStorage>)initWithService:(NSString *)service;
+
+/** @fn dataForKey:error:
+ @brief Gets the data for @c key in the storage. The key is set for the attribute
+ @c kSecAttrAccount of a generic password query.
+ @param key The key to use.
+ @param error The address to store any error that occurs during the process, if not NULL.
+ If the operation was successful, its content is set to @c nil .
+ @return The data stored in the storage for @c key, if any.
+ */
+- (nullable NSData *)dataForKey:(NSString *)key error:(NSError **_Nullable)error;
+
+/** @fn setData:forKey:error:
+ @brief Sets the data for @c key in the storage. The key is set for the attribute
+ @c kSecAttrAccount of a generic password query.
+ @param data The data to store.
+ @param key The key to use.
+ @param error The address to store any error that occurs during the process, if not NULL.
+ @return Whether the operation succeeded or not.
+ */
+- (BOOL)setData:(NSData *)data forKey:(NSString *)key error:(NSError **_Nullable)error;
+
+/** @fn removeDataForKey:error:
+ @brief Removes the data for @c key in the storage. The key is set for the attribute
+ @c kSecAttrAccount of a generic password query.
+ @param key The key to use.
+ @param error The address to store any error that occurs during the process, if not NULL.
+ @return Whether the operation succeeded or not.
+ */
+- (BOOL)removeDataForKey:(NSString *)key error:(NSError **_Nullable)error;
+
+@end
+
+/** @class FIRAuthKeychain
+ @brief The utility class to manipulate data in iOS Keychain.
+ */
+@interface FIRAuthKeychain : NSObject <FIRAuthStorage>
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/Private/FIRAuthNotificationManager.h b/Firebase/Auth/Source/Private/FIRAuthNotificationManager.h
new file mode 100644
index 0000000..42e5db8
--- /dev/null
+++ b/Firebase/Auth/Source/Private/FIRAuthNotificationManager.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+@class FIRAuthAppCredentialManager;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @typedef FIRAuthNotificationForwardingCallback
+ @brief The type of block to receive whether or not remote notifications are being forwarded.
+ @param isNotificationBeingForwarded Whether or not remote notifications are being forwarded.
+ */
+typedef void (^FIRAuthNotificationForwardingCallback)(BOOL isNotificationBeingForwarded);
+
+/** @class FIRAuthNotificationManager
+ */
+@interface FIRAuthNotificationManager : NSObject
+
+/** @property timeout
+ @brief The timeout for checking for notification forwarding.
+ @remarks Only tests should access this property.
+ */
+@property(nonatomic, assign) NSTimeInterval timeout;
+
+/** @fn initWithApplication:appCredentialManager:
+ @brief Initializes the instance.
+ @param application The application.
+ @param appCredentialManager The object to handle app credentials delivered via notification.
+ @return The initialized instance.
+ */
+- (instancetype)initWithApplication:(UIApplication *)application
+ appCredentialManager:(FIRAuthAppCredentialManager *)appCredentialManager
+ NS_DESIGNATED_INITIALIZER;
+
+/** @fn init
+ @brief please use initWithAppCredentialManager: instead.
+ */
+- (instancetype)init NS_UNAVAILABLE;
+
+/** @fn checkNotificationForwardingWithCallback:
+ @brief Checks whether or not remote notifications are being forwarded to this class.
+ @param callback The block to be called either immediately or in future once a result
+ is available.
+ */
+- (void)checkNotificationForwardingWithCallback:(FIRAuthNotificationForwardingCallback)callback;
+
+/** @fn canHandleNotification:
+ @brief Attempts to handle the remote notification.
+ @param notification The notification in question.
+ @return Whether or the notification has been handled.
+ */
+- (BOOL)canHandleNotification:(NSDictionary *)notification;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/Private/FIRAuthSerialTaskQueue.h b/Firebase/Auth/Source/Private/FIRAuthSerialTaskQueue.h
new file mode 100644
index 0000000..cdae046
--- /dev/null
+++ b/Firebase/Auth/Source/Private/FIRAuthSerialTaskQueue.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @typedef FIRAuthSerialTaskCompletionBlock
+ @brief The type of method a @c FIRAuthSerialTask must call when it is complete.
+ */
+typedef void (^FIRAuthSerialTaskCompletionBlock)(void);
+
+/** @typedef FIRAuthSerialTask
+ @brief Represents a unit of work submitted to a task queue.
+ @param complete The task MUST call the complete method when done.
+ */
+typedef void (^FIRAuthSerialTask)(FIRAuthSerialTaskCompletionBlock complete);
+
+/** @class FIRAuthSerialTaskQueue
+ @brief An easy to use serial task queue which supports a callback-based completion notification
+ system for easy asyncronous call chaining.
+ */
+@interface FIRAuthSerialTaskQueue : NSObject
+
+/** @fn enqueueTask:
+ @brief Enqueues a task for serial execution in the queue.
+ @remarks The task MUST call the complete method when done. This method is thread-safe.
+ The task block won't be executed concurrently with any other blocks in other task queues or
+ the global work queue as returned by @c FIRAuthGlobalWorkQueue , but an uncompleted task
+ (e.g. task block finished executation before complete method is called at a later time)
+ does not affect other task queues or the global work queue.
+ */
+- (void)enqueueTask:(FIRAuthSerialTask)task;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/Private/FIRAuthUserDefaultsStorage.h b/Firebase/Auth/Source/Private/FIRAuthUserDefaultsStorage.h
new file mode 100644
index 0000000..13774ab
--- /dev/null
+++ b/Firebase/Auth/Source/Private/FIRAuthUserDefaultsStorage.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+// This class is only available in the simulator.
+#if TARGET_OS_SIMULATOR
+#ifndef FIRAUTH_USER_DEFAULTS_STORAGE_AVAILABLE
+#define FIRAUTH_USER_DEFAULTS_STORAGE_AVAILABLE 1
+#endif
+#endif
+
+#if FIRAUTH_USER_DEFAULTS_STORAGE_AVAILABLE
+
+#import "FIRAuthKeychain.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @class FIRAuthUserDefaultsStorage
+ @brief The utility class to storage data in NSUserDefaults.
+ */
+@interface FIRAuthUserDefaultsStorage : NSObject <FIRAuthStorage>
+
+/** @fn clear
+ @brief Clears all data from the storage.
+ @remarks This method is only supposed to be called from tests.
+ */
+- (void)clear;
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+#endif // FIRAUTH_USER_DEFAULTS_STORAGE_AVAILABLE
diff --git a/Firebase/Auth/Source/Private/FIRAuth_Internal.h b/Firebase/Auth/Source/Private/FIRAuth_Internal.h
new file mode 100644
index 0000000..bdbefce
--- /dev/null
+++ b/Firebase/Auth/Source/Private/FIRAuth_Internal.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRAuth.h"
+
+@class FIRAuthAPNSTokenManager;
+@class FIRAuthAppCredentialManager;
+@class FIRAuthNotificationManager;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @var FIRAuthStateDidChangeInternalNotification
+ @brief The name of the @c NSNotificationCenter notification which is posted when the auth state
+ changes (e.g. a new token has been produced, a user logs in or out). The object parameter of
+ the notification is a dictionary possibly containing the key:
+ @c FIRAuthStateDidChangeInternalNotificationTokenKey (the new access token.) If it does not
+ contain this key it indicates a sign-out event took place.
+ */
+extern NSString *const FIRAuthStateDidChangeInternalNotification;
+
+/** @var FIRAuthStateDidChangeInternalNotificationTokenKey
+ @brief A key present in the dictionary object parameter of the
+ @c FIRAuthStateDidChangeInternalNotification notification. The value associated with this
+ key will contain the new access token.
+ */
+extern NSString *const FIRAuthStateDidChangeInternalNotificationTokenKey;
+
+@interface FIRAuth ()
+
+/** @property APIKey
+ @brief The Google API key.
+ @remarks Needed for calls to identity toolkit and secure token service.
+ */
+@property(nonatomic, copy, readonly) NSString *APIKey;
+
+/** @property tokenManager
+ @brief The manager for APNs tokens used by phone number auth.
+ */
+@property(nonatomic, strong, readonly) FIRAuthAPNSTokenManager *tokenManager;
+
+/** @property appCredentailManager
+ @brief The manager for app credentials used by phone number auth.
+ */
+@property(nonatomic, strong, readonly) FIRAuthAppCredentialManager *appCredentialManager;
+
+/** @property notificationManager
+ @brief The manager for remote notifications used by phone number auth.
+ */
+@property(nonatomic, strong, readonly) FIRAuthNotificationManager *notificationManager;
+
+/** @fn initWithAPIKey:appName:
+ @brief Designated initializer.
+ @param APIKey The Google Developers Console API key for making requests from your app.
+ @param appName The name property of the previously created @c FIRApp instance.
+ */
+- (nullable instancetype)initWithAPIKey:(NSString *)APIKey
+ appName:(NSString *)appName NS_DESIGNATED_INITIALIZER;
+
+/** @fn notifyListenersOfAuthStateChange
+ @brief Posts the @c FIRAuthStateDidChangeNotification notification.
+ @remarks Called by @c FIRUser when token changes occur.
+ @param user The user whose tokens changed.
+ @param token The new access token associated with the user.
+ */
+- (void)notifyListenersOfAuthStateChangeWithUser:(nullable FIRUser *)user
+ token:(nullable NSString *)token;
+
+/** @fn updateKeychainWithUser:error:
+ @brief Updates the keychain for the given user.
+ @param user The user to be updated.
+ @param error The error caused the method to fail if the method returns NO.
+ @return Whether updating keychain has succeeded or not.
+ @remarks Called by @c FIRUser when user info or token changes occur.
+ */
+- (BOOL)updateKeychainWithUser:(FIRUser *)user error:(NSError *_Nullable *_Nullable)error;
+
+/** @fn internalSignInWithCredential:callback:
+ @brief Convenience method for @c internalSignInAndRetrieveDataWithCredential:callback:
+ This method doesn't return additional identity provider data.
+*/
+- (void)internalSignInWithCredential:(FIRAuthCredential *)credential
+ callback:(FIRAuthResultCallback)callback;
+
+/** @fn internalSignInAndRetrieveDataWithCredential:callback:
+ @brief Asynchronously signs in Firebase with the given 3rd party credentials (e.g. a Facebook
+ login Access Token, a Google ID Token/Access Token pair, etc.) and returns additional
+ identity provider data.
+ @param credential The credential supplied by the IdP.
+ @param isReauthentication Indicates whether or not the current invocation originated from an
+ attempt to reauthenticate.
+ @param callback A block which is invoked when the sign in finishes (or is cancelled.) Invoked
+ asynchronously on the auth global work queue in the future.
+ @remarks This is the internal counterpart of this method, which uses a callback that does not
+ update the current user.
+ */
+- (void)internalSignInAndRetrieveDataWithCredential:(FIRAuthCredential *)credential
+ isReauthentication:(BOOL)isReauthentication
+ callback:(nullable FIRAuthDataResultCallback)callback;
+
+/** @fn signOutByForceWithUserID:error:
+ @brief Signs out the current user.
+ @param userID The ID of the user to force sign out.
+ @param error An optional out parameter for error results.
+ @return @YES when the sign out request was successful. @NO otherwise.
+ */
+- (BOOL)signOutByForceWithUserID:(NSString *)userID error:(NSError *_Nullable *_Nullable)error;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/Private/FIRUser_Internal.h b/Firebase/Auth/Source/Private/FIRUser_Internal.h
new file mode 100644
index 0000000..1447607
--- /dev/null
+++ b/Firebase/Auth/Source/Private/FIRUser_Internal.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRUser.h"
+
+@class FIRAuth;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @typedef FIRRetrieveUserCallback
+ @brief The type of block that is invoked when the construction of a user succeeds or fails.
+ @param user The user that was constructed, or nil if user construction failed.
+ @param error The error which occurred, or nil if the request was successful.
+ */
+typedef void(^FIRRetrieveUserCallback)(FIRUser *_Nullable user, NSError *_Nullable error);
+
+@interface FIRUser () <NSSecureCoding>
+
+/** @property rawAccessToken
+ @brief The cached access token.
+ @remarks This method is specifically for providing the access token to internal clients during
+ deserialization and sign-in events, and should not be used to retrieve the access token by
+ anyone else.
+ */
+@property(nonatomic, copy, readonly) NSString *rawAccessToken;
+
+/** @property auth
+ @brief A weak reference to a FIRAuth instance which is used to notify auth of token changes.
+ */
+@property(nonatomic, weak) FIRAuth *auth;
+
+/** @var accessTokenExpirationDate
+ @brief The expiration date of the cached access token.
+ */
+@property(nonatomic, copy, readonly) NSDate *accessTokenExpirationDate;
+
+/** @fn retrieveUserWithAPIKey:accessToken:accessTokenExpirationDate:refreshToken:callback:
+ @brief Constructs a user with Secure Token Service tokens, and obtains user details from the
+ getAccountInfo endpoint.
+ @param APIKey The client API key for making RPCs.
+ @param accessToken The Secure Token Service access token.
+ @param accessTokenExpirationDate The approximate expiration date of the access token.
+ @param refreshToken The Secure Token Service refresh token.
+ @param anonymous Whether or not the user is anonymous.
+ @param callback A block which is invoked when the construction succeeds or fails. Invoked
+ asynchronously on the auth global work queue in the future.
+ */
++ (void)retrieveUserWithAPIKey:(NSString *)APIKey
+ accessToken:(NSString *)accessToken
+ accessTokenExpirationDate:(NSDate *)accessTokenExpirationDate
+ refreshToken:(NSString *)refreshToken
+ anonymous:(BOOL)anonymous
+ callback:(FIRRetrieveUserCallback)callback;
+
+/** @fn internalGetTokenForcingRefresh:callback:
+ @brief Retrieves the Firebase authentication token, possibly refreshing it if it has expired.
+ @param forceRefresh Forces a token refresh. Useful if the token becomes invalid for some reason
+ other than an expiration.
+ @param callback The block to invoke when the token is available. Invoked asynchronously on the
+ global work thread in the future.
+ */
+- (void)internalGetTokenForcingRefresh:(BOOL)forceRefresh
+ callback:(nonnull FIRAuthTokenCallback)callback;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/RPCs/FIRAuthBackend.h b/Firebase/Auth/Source/RPCs/FIRAuthBackend.h
new file mode 100644
index 0000000..519a6e7
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRAuthBackend.h
@@ -0,0 +1,496 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+@class FIRCreateAuthURIRequest;
+@class FIRCreateAuthURIResponse;
+@class FIRGetAccountInfoRequest;
+@class FIRGetAccountInfoResponse;
+@class FIRGetOOBConfirmationCodeRequest;
+@class FIRGetOOBConfirmationCodeResponse;
+@class FIRResetPasswordRequest;
+@class FIRResetPasswordResponse;
+@class FIRSecureTokenRequest;
+@class FIRSecureTokenResponse;
+@class FIRSetAccountInfoRequest;
+@class FIRSetAccountInfoResponse;
+@class FIRVerifyAssertionRequest;
+@class FIRVerifyAssertionResponse;
+@class FIRVerifyClientRequest;
+@class FIRVerifyClientResponse;
+@class FIRVerifyCustomTokenRequest;
+@class FIRVerifyCustomTokenResponse;
+@class FIRVerifyPasswordRequest;
+@class FIRVerifyPasswordResponse;
+@class FIRVerifyPhoneNumberRequest;
+@class FIRVerifyPhoneNumberResponse;
+@class FIRSendVerificationCodeRequest;
+@class FIRSendVerificationCodeResponse;
+@class FIRSignUpNewUserRequest;
+@class FIRSignUpNewUserResponse;
+@class FIRDeleteAccountRequest;
+@class FIRDeleteAccountResponse;
+@protocol FIRAuthBackendImplementation;
+@protocol FIRAuthBackendRPCIssuer;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @typedef FIRAuthBackendRPCIssuerCompletionHandler
+ @brief The type of block used to return the result of a call to an endpoint.
+ @param data The HTTP response body.
+ @param error The error which occurred, if any.
+ @remarks One of response or error will be non-nil.
+ */
+typedef void (^FIRAuthBackendRPCIssuerCompletionHandler)(NSData *_Nullable data,
+ NSError *_Nullable error);
+
+/** @typedef FIRCreateAuthURIResponseCallback
+ @brief The type of block used to return the result of a call to the createAuthURI
+ endpoint.
+ @param response The received response, if any.
+ @param error The error which occurred, if any.
+ @remarks One of response or error will be non-nil.
+ */
+typedef void (^FIRCreateAuthURIResponseCallback)
+ (FIRCreateAuthURIResponse *_Nullable response, NSError *_Nullable error);
+
+/** @typedef FIRGetAccountInfoResponseCallback
+ @brief The type of block used to return the result of a call to the getAccountInfo
+ endpoint.
+ @param response The received response, if any.
+ @param error The error which occurred, if any.
+ @remarks One of response or error will be non-nil.
+ */
+typedef void (^FIRGetAccountInfoResponseCallback)
+ (FIRGetAccountInfoResponse *_Nullable response, NSError *_Nullable error);
+
+/** @typedef FIRSetAccountInfoResponseCallback
+ @brief The type of block used to return the result of a call to the setAccountInfo
+ endpoint.
+ @param response The received response, if any.
+ @param error The error which occurred, if any.
+ @remarks One of response or error will be non-nil.
+ */
+typedef void (^FIRSetAccountInfoResponseCallback)
+ (FIRSetAccountInfoResponse *_Nullable response, NSError *_Nullable error);
+
+/** @typedef FIRSecureTokenResponseCallback
+ @brief The type of block used to return the result of a call to the token endpoint.
+ @param response The received response, if any.
+ @param error The error which occurred, if any.
+ @remarks One of response or error will be non-nil.
+ */
+typedef void (^FIRSecureTokenResponseCallback)
+ (FIRSecureTokenResponse *_Nullable response, NSError *_Nullable error);
+
+/** @typedef FIRVerifyAssertionResponseCallback
+ @brief The type of block used to return the result of a call to the verifyAssertion
+ endpoint.
+ @param response The received response, if any.
+ @param error The error which occurred, if any.
+ @remarks One of response or error will be non-nil.
+ */
+typedef void (^FIRVerifyAssertionResponseCallback)
+ (FIRVerifyAssertionResponse *_Nullable response, NSError *_Nullable error);
+
+/** @typedef FIRVerifyPasswordResponseCallback
+ @brief The type of block used to return the result of a call to the verifyPassword
+ endpoint.
+ @param response The received response, if any.
+ @param error The error which occurred, if any.
+ @remarks One of response or error will be non-nil.
+ */
+typedef void (^FIRVerifyPasswordResponseCallback)
+ (FIRVerifyPasswordResponse *_Nullable response, NSError *_Nullable error);
+
+/** @typedef FIRVerifyCustomTokenResponseCallback
+ @brief The type of block used to return the result of a call to the verifyCustomToken
+ endpoint.
+ @param response The received response, if any.
+ @param error The error which occurred, if any.
+ @remarks One of response or error will be non-nil.
+ */
+typedef void (^FIRVerifyCustomTokenResponseCallback)
+ (FIRVerifyCustomTokenResponse *_Nullable response, NSError *_Nullable error);
+
+/** @typedef FIRDeleteCallBack
+ @brief The type of block called when a request delete account has finished.
+ @param error The error which occurred, or nil if the request was successful.
+ */
+typedef void (^FIRDeleteCallBack)(NSError *_Nullable error);
+
+/** @typedef FIRGetOOBConfirmationCodeResponseCallback
+ @brief The type of block used to return the result of a call to the getOOBConfirmationCode
+ endpoint.
+ @param response The received response, if any.
+ @param error The error which occurred, if any.
+ @remarks One of response or error will be non-nil.
+ */
+typedef void (^FIRGetOOBConfirmationCodeResponseCallback)
+ (FIRGetOOBConfirmationCodeResponse *_Nullable response, NSError *_Nullable error);
+
+/** @typedef FIRSignupNewUserCallback
+ @brief The type of block used to return the result of a call to the signupNewUser endpoint.
+ @param response The received response, if any.
+ @param error The error which occurred, if any.
+ @remarks One of response or error will be non-nil.
+ */
+typedef void (^FIRSignupNewUserCallback)
+ (FIRSignUpNewUserResponse *_Nullable response, NSError *_Nullable error);
+
+/** @typedef FIRResetPasswordCallback
+ @brief The type of block used to return the result of a call to the resetPassword endpoint.
+ @param response The received response, if any.
+ @param error The error which occurred, if any.
+ @remarks One of response or error will be non-nil.
+ */
+typedef void (^FIRResetPasswordCallback)
+ (FIRResetPasswordResponse *_Nullable response, NSError *_Nullable error);
+
+/** @typedef FIRSendVerificationCodeResponseCallback
+ @brief The type of block used to return the result of a call to the sendVerificationCode
+ endpoint.
+ @param response The received response, if any.
+ @param error The error which occurred, if any.
+ @remarks One of response or error will be non-nil.
+ */
+typedef void (^FIRSendVerificationCodeResponseCallback)
+ (FIRSendVerificationCodeResponse *_Nullable response, NSError *_Nullable error);
+
+/** @typedef FIRVerifyPhoneNumberResponseCallback
+ @brief The type of block used to return the result of a call to the verifyPhoneNumber endpoint.
+ @param response The received response, if any.
+ @param error The error which occurred, if any.
+ @remarks One of response or error will be non-nil.
+ */
+typedef void (^FIRVerifyPhoneNumberResponseCallback)
+ (FIRVerifyPhoneNumberResponse *_Nullable response, NSError *_Nullable error);
+
+/** @typedef FIRVerifyClientResponseCallback
+ @brief The type of block used to return the result of a call to the verifyClient endpoint.
+ @param response The received response, if any.
+ @param error The error which occurred, if any.
+ @remarks One of response or error will be non-nil.
+ */
+typedef void (^FIRVerifyClientResponseCallback)
+ (FIRVerifyClientResponse *_Nullable response, NSError *_Nullable error);
+
+/** @class FIRAuthBackend
+ @brief Simple static class with methods representing the backend RPCs.
+ @remarks All callback blocks passed as method parameters are invoked asynchronously on the
+ global work queue in the future. See
+ https://github.com/firebase/firebase-ios-sdk/tree/master/Firebase/Auth/Docs/threading.ml
+ */
+@interface FIRAuthBackend : NSObject
+
+/** @fn setBackendImplementation:
+ @brief Changes the default backend implementation to something else.
+ @param backendImplementation The backend implementation to use.
+ @remarks This is not, generally, safe to call in a scenario where other backend requests may
+ be occuring. This is specifically to help mock the backend for testing purposes.
+ */
++ (void)setBackendImplementation:(id<FIRAuthBackendImplementation>)backendImplementation;
+
+/** @fn setDefaultBackendImplementationWithRPCIssuer:
+ @brief Uses the default backend implementation, but with a custom RPC issuer.
+ @param RPCIssuer The RPC issuer to use. If @c nil, will use the default implementation.
+ @remarks This is not, generally, safe to call in a scenario where other backend requests may
+ be occuring. This is specifically to help test the backend interfaces (requests, responses,
+ and shared FIRAuthBackend logic.)
+ */
++ (void)setDefaultBackendImplementationWithRPCIssuer:
+ (nullable id<FIRAuthBackendRPCIssuer>)RPCIssuer;
+
+/** @fn createAuthURI:callback:
+ @brief Calls the createAuthURI endpoint, which is responsible for creating the URI used by the
+ IdP to authenticate the user.
+ @param request The request parameters.
+ @param callback The callback.
+ */
++ (void)createAuthURI:(FIRCreateAuthURIRequest *)request
+ callback:(FIRCreateAuthURIResponseCallback)callback;
+
+/** @fn getAccountInfo:callback:
+ @brief Calls the getAccountInfo endpoint, which returns account info for a given account.
+ @param request The request parameters.
+ @param callback The callback.
+ */
++ (void)getAccountInfo:(FIRGetAccountInfoRequest *)request
+ callback:(FIRGetAccountInfoResponseCallback)callback;
+
+/** @fn setAccountInfo:callback:
+ @brief Calls the setAccountInfo endpoint, which is responsible for setting account info for a
+ user, for example, to sign up a new user with email and password.
+ @param request The request parameters.
+ @param callback The callback.
+ */
++ (void)setAccountInfo:(FIRSetAccountInfoRequest *)request
+ callback:(FIRSetAccountInfoResponseCallback)callback;
+
+/** @fn verifyAssertion:callback:
+ @brief Calls the verifyAssertion endpoint, which is responsible for authenticating a
+ user who has IDP-related credentials (an ID Token, an Access Token, etc.)
+ @param request The request parameters.
+ @param callback The callback.
+ */
++ (void)verifyAssertion:(FIRVerifyAssertionRequest *)request
+ callback:(FIRVerifyAssertionResponseCallback)callback;
+
+/** @fn verifyCustomToken:callback:
+ @brief Calls the verifyCustomToken endpoint, which is responsible for authenticating a
+ user who has BYOAuth credentials (a self-signed token using their BYOAuth private key.)
+ @param request The request parameters.
+ @param callback The callback.
+ */
++ (void)verifyCustomToken:(FIRVerifyCustomTokenRequest *)request
+ callback:(FIRVerifyCustomTokenResponseCallback)callback;
+
+/** @fn verifyPassword:callback:
+ @brief Calls the verifyPassword endpoint, which is responsible for authenticating a
+ user who has email and password credentials.
+ @param request The request parameters.
+ @param callback The callback.
+ */
++ (void)verifyPassword:(FIRVerifyPasswordRequest *)request
+ callback:(FIRVerifyPasswordResponseCallback)callback;
+
+/** @fn secureToken:callback:
+ @brief Calls the token endpoint, which is responsible for performing STS token exchanges and
+ token refreshes.
+ @param request The request parameters.
+ @param callback The callback.
+ */
++ (void)secureToken:(FIRSecureTokenRequest *)request
+ callback:(FIRSecureTokenResponseCallback)callback;
+
+/** @fn getOOBConfirmationCode:callback:
+ @brief Calls the getOOBConfirmationCode endpoint, which is responsible for sending email change
+ request emails, and password reset emails.
+ @param request The request parameters.
+ @param callback The callback.
+ */
++ (void)getOOBConfirmationCode:(FIRGetOOBConfirmationCodeRequest *)request
+ callback:(FIRGetOOBConfirmationCodeResponseCallback)callback;
+
+/** @fn signUpNewUser:
+ @brief Calls the signUpNewUser endpoint, which is responsible anonymously signing up a user
+ or signing in a user anonymously.
+ @param request The request parameters.
+ @param callback The callback.
+ */
++ (void)signUpNewUser:(FIRSignUpNewUserRequest *)request
+ callback:(FIRSignupNewUserCallback)callback;
+
+/** @fn resetPassword:callback
+ @brief Calls the resetPassword endpoint, which is responsible for resetting a user's password
+ given an OOB code and new password.
+ @param request The request parameters.
+ @param callback The callback.
+ */
++ (void)resetPassword:(FIRResetPasswordRequest *)request
+ callback:(FIRResetPasswordCallback)callback;
+
+/** @fn deleteAccount:
+ @brief Calls the DeleteAccount endpoint, which is responsible for deleting a user.
+ @param request The request parameters.
+ @param callback The callback.
+ */
++ (void)deleteAccount:(FIRDeleteAccountRequest *)request
+ callback:(FIRDeleteCallBack)callback;
+
+/** @fn sendVerificationCode:callback:
+ @brief Calls the sendVerificationCode endpoint, which is responsible for sending the
+ verification code to a phone number specified in the request parameters.
+ @param request The request parameters.
+ @param callback The callback.
+ */
++ (void)sendVerificationCode:(FIRSendVerificationCodeRequest *)request
+ callback:(FIRSendVerificationCodeResponseCallback)callback;
+
+/** @fn verifyPhoneNumber:callback:
+ @brief Calls the verifyPhoneNumber endpoint, which is responsible for sending the verification
+ code to a phone number specified in the request parameters.
+ @param request The request parameters.
+ @param callback The callback.
+ */
++ (void)verifyPhoneNumber:(FIRVerifyPhoneNumberRequest *)request
+ callback:(FIRVerifyPhoneNumberResponseCallback)callback;
+
+/** @fn verifyClient:callback:
+ @brief Calls the verifyClient endpoint, which is responsible for sending the silent push
+ notification used for app validation to the device provided in the request parameters.
+ @param request The request parameters.
+ @param callback The callback.
+ */
++ (void)verifyClient:(FIRVerifyClientRequest *)request
+ callback:(FIRVerifyClientResponseCallback)callback;
+
+@end
+
+/** @protocol FIRAuthBackendRPCIssuer
+ @brief Used to make FIRAuthBackend
+ */
+@protocol FIRAuthBackendRPCIssuer <NSObject>
+
+/** @fn asyncPostToURL:body:contentType:completionHandler:
+ @brief Asynchronously sends a POST request.
+ @param URL URL of the request.
+ @param body Request body.
+ @param contentType Content type of the body.
+ @param handler provided that handles POST response. Invoked asynchronously on the auth global
+ work queue in the future.
+ */
+- (void)asyncPostToURL:(NSURL *)URL
+ body:(NSData *)body
+ contentType:(NSString *)contentType
+ completionHandler:(FIRAuthBackendRPCIssuerCompletionHandler)handler;
+
+@end
+
+/** @protocol FIRAuthBackendImplementation
+ @brief Used to make FIRAuthBackend provide a layer of indirection to an actual RPC-based backend
+ or a mock backend.
+ */
+@protocol FIRAuthBackendImplementation <NSObject>
+
+/** @fn createAuthURI:callback:
+ @brief Calls the createAuthURI endpoint, which is responsible for creating the URI used by the
+ IdP to authenticate the user.
+ @param request The request parameters.
+ @param callback The callback.
+ */
+- (void)createAuthURI:(FIRCreateAuthURIRequest *)request
+ callback:(FIRCreateAuthURIResponseCallback)callback;
+
+/** @fn getAccountInfo:callback:
+ @brief Calls the getAccountInfo endpoint, which returns account info for a given account.
+ @param request The request parameters.
+ @param callback The callback.
+ */
+- (void)getAccountInfo:(FIRGetAccountInfoRequest *)request
+ callback:(FIRGetAccountInfoResponseCallback)callback;
+
+/** @fn setAccountInfo:callback:
+ @brief Calls the setAccountInfo endpoint, which is responsible for setting account info for a
+ user, for example, to sign up a new user with email and password.
+ @param request The request parameters.
+ @param callback The callback.
+ */
+- (void)setAccountInfo:(FIRSetAccountInfoRequest *)request
+ callback:(FIRSetAccountInfoResponseCallback)callback;
+
+/** @fn verifyAssertion:callback:
+ @brief Calls the verifyAssertion endpoint, which is responsible for authenticating a
+ user who has IDP-related credentials (an ID Token, an Access Token, etc.)
+ @param request The request parameters.
+ @param callback The callback.
+ */
+- (void)verifyAssertion:(FIRVerifyAssertionRequest *)request
+ callback:(FIRVerifyAssertionResponseCallback)callback;
+
+/** @fn verifyCustomToken:callback:
+ @brief Calls the verifyCustomToken endpoint, which is responsible for authenticating a
+ user who has BYOAuth credentials (a self-signed token using their BYOAuth private key.)
+ @param request The request parameters.
+ @param callback The callback.
+ */
+- (void)verifyCustomToken:(FIRVerifyCustomTokenRequest *)request
+ callback:(FIRVerifyCustomTokenResponseCallback)callback;
+
+/** @fn verifyPassword:callback:
+ @brief Calls the verifyPassword endpoint, which is responsible for authenticating a
+ user who has email and password credentials.
+ @param request The request parameters.
+ @param callback The callback.
+ */
+- (void)verifyPassword:(FIRVerifyPasswordRequest *)request
+ callback:(FIRVerifyPasswordResponseCallback)callback;
+
+/** @fn secureToken:callback:
+ @brief Calls the token endpoint, which is responsible for performing STS token exchanges and
+ token refreshes.
+ @param request The request parameters.
+ @param callback The callback.
+ */
+- (void)secureToken:(FIRSecureTokenRequest *)request
+ callback:(FIRSecureTokenResponseCallback)callback;
+
+/** @fn getOOBConfirmationCode:callback:
+ @brief Calls the getOOBConfirmationCode endpoint, which is responsible for sending email change
+ request emails, and password reset emails.
+ @param request The request parameters.
+ @param callback The callback.
+ */
+- (void)getOOBConfirmationCode:(FIRGetOOBConfirmationCodeRequest *)request
+ callback:(FIRGetOOBConfirmationCodeResponseCallback)callback;
+
+/** @fn signUpNewUser:
+ @brief Calls the signUpNewUser endpoint, which is responsible anonymously signing up a user
+ or signing in a user anonymously.
+ @param request The request parameters.
+ @param callback The callback.
+ */
+- (void)signUpNewUser:(FIRSignUpNewUserRequest *)request
+ callback:(FIRSignupNewUserCallback)callback;
+
+/** @fn deleteAccount:
+ @brief Calls the DeleteAccount endpoint, which is responsible for deleting a user.
+ @param request The request parameters.
+ @param callback The callback.
+ */
+- (void)deleteAccount:(FIRDeleteAccountRequest *)request
+ callback:(FIRDeleteCallBack)callback;
+
+/** @fn sendVerificationCode:callback:
+ @brief Calls the sendVerificationCode endpoint, which is responsible for sending the
+ verification code to a phone number specified in the request parameters.
+ @param request The request parameters.
+ @param callback The callback.
+ */
+- (void)sendVerificationCode:(FIRSendVerificationCodeRequest *)request
+ callback:(FIRSendVerificationCodeResponseCallback)callback;
+
+/** @fn verifyPhoneNumber:callback:
+ @brief Calls the verifyPhoneNumber endpoint, which is responsible for sending the verification
+ code to a phone number specified in the request parameters.
+ @param request The request parameters.
+ @param callback The callback.
+ */
+- (void)verifyPhoneNumber:(FIRVerifyPhoneNumberRequest *)request
+ callback:(FIRVerifyPhoneNumberResponseCallback)callback;
+
+/** @fn verifyClient:callback:
+ @brief Calls the verifyClient endpoint, which is responsible for sending the silent push
+ notification used for app validation to the device provided in the request parameters.
+ @param request The request parameters.
+ @param callback The callback.
+ */
+- (void)verifyClient:(FIRVerifyClientRequest *)request
+ callback:(FIRVerifyClientResponseCallback)callback;
+
+/** @fn resetPassword:callback
+ @brief Calls the resetPassword endpoint, which is responsible for resetting a user's password
+ given an OOB code and new password.
+ @param request The request parameters.
+ @param callback The callback.
+ */
+- (void)resetPassword:(FIRResetPasswordRequest *)request
+ callback:(FIRResetPasswordCallback)callback;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/RPCs/FIRAuthBackend.m b/Firebase/Auth/Source/RPCs/FIRAuthBackend.m
new file mode 100644
index 0000000..3efc602
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRAuthBackend.m
@@ -0,0 +1,943 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRAuthBackend.h"
+
+#import "../AuthProviders/Phone/FIRPhoneAuthCredential_Internal.h"
+#import "../AuthProviders/Phone/FIRPhoneAuthProvider.h"
+#import "../Private/FIRAuthErrorUtils.h"
+#import "../Private/FIRAuthGlobalWorkQueue.h"
+#import "FirebaseAuth.h"
+#import "FIRAuthRPCRequest.h"
+#import "FIRAuthRPCResponse.h"
+#import "FIRCreateAuthURIRequest.h"
+#import "FIRCreateAuthURIResponse.h"
+#import "FIRDeleteAccountRequest.h"
+#import "FIRDeleteAccountResponse.h"
+#import "FIRGetAccountInfoRequest.h"
+#import "FIRGetAccountInfoResponse.h"
+#import "FIRGetOOBConfirmationCodeRequest.h"
+#import "FIRGetOOBConfirmationCodeResponse.h"
+#import "FIRResetPasswordRequest.h"
+#import "FIRResetPasswordResponse.h"
+#import "FIRSendVerificationCodeRequest.h"
+#import "FIRSendVerificationCodeResponse.h"
+#import "FIRSecureTokenRequest.h"
+#import "FIRSecureTokenResponse.h"
+#import "FIRSetAccountInfoRequest.h"
+#import "FIRSetAccountInfoResponse.h"
+#import "FIRSignUpNewUserRequest.h"
+#import "FIRSignUpNewUserResponse.h"
+#import "FIRVerifyAssertionRequest.h"
+#import "FIRVerifyAssertionResponse.h"
+#import "FIRVerifyClientRequest.h"
+#import "FIRVerifyClientResponse.h"
+#import "FIRVerifyCustomTokenRequest.h"
+#import "FIRVerifyCustomTokenResponse.h"
+#import "FIRVerifyPasswordRequest.h"
+#import "FIRVerifyPasswordResponse.h"
+#import "FIRVerifyPhoneNumberRequest.h"
+#import "FIRVerifyPhoneNumberResponse.h"
+#import <GTMSessionFetcher/GTMSessionFetcher.h>
+#import <GTMSessionFetcher/GTMSessionFetcherService.h>
+
+/** @var kIosBundleIdentifierHeader
+ @brief HTTP header name for iOS bundle ID.
+ */
+static NSString *const kIosBundleIdentifierHeader = @"X-Ios-Bundle-Identifier";
+
+/** @var kJSONContentType
+ @brief The value of the HTTP content-type header for JSON payloads.
+ */
+static NSString *const kJSONContentType = @"application/json";
+
+/** @var kErrorDataKey
+ @brief Key for error data in NSError returned by @c GTMSessionFetcher.
+ */
+static NSString * const kErrorDataKey = @"data";
+
+/** @var kErrorKey
+ @brief The key for the "error" value in JSON responses from the server.
+ */
+static NSString *const kErrorKey = @"error";
+
+/** @var kErrorsKey
+ @brief The key for the "errors" value in JSON responses from the server.
+ */
+static NSString *const kErrorsKey = @"errors";
+
+/** @var kReasonKey
+ @brief The key for the "reason" value in JSON responses from the server.
+ */
+static NSString *const kReasonKey = @"reason";
+
+/** @var kInvalidKeyReasonValue
+ @brief The value for the "reason" key indicating an invalid API Key was received by the server.
+ */
+static NSString *const kInvalidKeyReasonValue = @"keyInvalid";
+
+/** @var kAppNotAuthorizedReasonValue
+ @brief The value for the "reason" key indicating the App is not authorized to use Firebase
+ Authentication.
+ */
+static NSString *const kAppNotAuthorizedReasonValue = @"ipRefererBlocked";
+
+/** @var kErrorMessageKey
+ @brief The key for an error's "message" value in JSON responses from the server.
+ */
+static NSString *const kErrorMessageKey = @"message";
+
+/** @var kUserNotFoundErrorMessage
+ @brief This is the error message returned when the user is not found, which means the user
+ account has been deleted given the token was once valid.
+ */
+static NSString *const kUserNotFoundErrorMessage = @"USER_NOT_FOUND";
+
+/** @var kUserDeletedErrorMessage
+ @brief This is the error message the server will respond with if the user entered an invalid
+ email address.
+ */
+static NSString *const kUserDeletedErrorMessage = @"EMAIL_NOT_FOUND";
+
+/** @var kInvalidLocalIDErrorMessage
+ @brief This is the error message the server responds with if the user local id in the id token
+ does not exit.
+ */
+static NSString *const kInvalidLocalIDErrorMessage = @"INVALID_LOCAL_ID";
+
+/** @var kUserTokenExpiredErrorMessage
+ @brief The error returned by the server if the token issue time is older than the account's
+ valid_since time.
+ */
+static NSString *const kUserTokenExpiredErrorMessage = @"TOKEN_EXPIRED";
+
+/** @var kTooManyRequestsErrorMessage
+ @brief This is the error message the server will respond with if too many requests were made to
+ a server method.
+ */
+static NSString *const kTooManyRequestsErrorMessage = @"TOO_MANY_ATTEMPTS_TRY_LATER";
+
+/** @var kInvalidTokenCustomErrorMessage
+ @brief This is the error message the server will respond with if there is a validation error
+ with the custom token.
+ */
+static NSString *const kInvalidCustomTokenErrorMessage = @"INVALID_CUSTOM_TOKEN";
+
+/** @var kCustomTokenMismatch
+ @brief This is the error message the server will respond with if the service account and API key
+ belong to different projects.
+ */
+static NSString *const kCustomTokenMismatch = @"CREDENTIAL_MISMATCH";
+
+/** @var kInvalidCredentialErrorMessage
+ @brief This is the error message the server responds with if the IDP token or requestUri is
+ invalid.
+ */
+static NSString *const kInvalidCredentialErrorMessage = @"INVALID_IDP_RESPONSE";
+
+/** @var kUserDisabledErrorMessage
+ @brief The error returned by the server if the user account is diabled.
+ */
+static NSString *const kUserDisabledErrorMessage = @"USER_DISABLED";
+
+/** @var kOperationNotAllowedErrorMessage
+ @brief This is the error message the server will respond with if Admin disables IDP specified by
+ provider.
+ */
+static NSString *const kOperationNotAllowedErrorMessage = @"OPERATION_NOT_ALLOWED";
+
+/** @var kPasswordLoginDisabledErrorMessage
+ @brief This is the error message the server responds with if password login is disabled.
+ */
+static NSString *const kPasswordLoginDisabledErrorMessage = @"PASSWORD_LOGIN_DISABLED";
+
+/** @var kEmailAlreadyInUseErrorMessage
+ @brief This is the error message the server responds with if the email address already exists.
+ */
+static NSString *const kEmailAlreadyInUseErrorMessage = @"EMAIL_EXISTS";
+
+/** @var kInvalidEmailErrorMessage
+ @brief The error returned by the server if the email is invalid.
+ */
+static NSString *const kInvalidEmailErrorMessage = @"INVALID_EMAIL";
+
+/** @var kInvalidIdentifierErrorMessage
+ @brief The error returned by the server if the identifier is invalid.
+ */
+static NSString *const kInvalidIdentifierErrorMessage = @"INVALID_IDENTIFIER";
+
+/** @var kWrongPasswordErrorMessage
+ @brief This is the error message the server will respond with if the user entered a wrong
+ password.
+ */
+static NSString *const kWrongPasswordErrorMessage = @"INVALID_PASSWORD";
+
+/** @var kCredentialTooOldErrorMessage
+ @brief This is the error message the server responds with if account change is attempted 5
+ minutes after signing in.
+ */
+static NSString *const kCredentialTooOldErrorMessage = @"CREDENTIAL_TOO_OLD_LOGIN_AGAIN";
+
+/** @var kFederatedUserIDAlreadyLinkedMessage
+ @brief This is the error message the server will respond with if the federated user ID has been
+ already linked with another account.
+ */
+static NSString *const kFederatedUserIDAlreadyLinkedMessage = @"FEDERATED_USER_ID_ALREADY_LINKED";
+
+/** @var kInvalidUserTokenErrorMessage
+ @brief This is the error message the server responds with if user's saved auth credential is
+ invalid, and the user needs to sign in again.
+ */
+static NSString *const kInvalidUserTokenErrorMessage = @"INVALID_ID_TOKEN";
+
+/** @var kWeakPasswordErrorMessagePrefix
+ @brief This is the prefix for the error message the server responds with if user's new password
+ to be set is too weak.
+ */
+static NSString *const kWeakPasswordErrorMessagePrefix = @"WEAK_PASSWORD";
+
+/** @var kExpiredActionCodeErrorMessage
+ @brief This is the error message the server will respond with if the action code is expired.
+ */
+static NSString *const kExpiredActionCodeErrorMessage = @"EXPIRED_OOB_CODE";
+
+/** @var kInvalidActionCodeErrorMessage
+ @brief This is the error message the server will respond with if the action code is invalid.
+ */
+static NSString *const kInvalidActionCodeErrorMessage = @"INVALID_OOB_CODE";
+
+/** @var kInvalidSenderEmailErrorMessage
+ @brief This is the error message the server will respond with if the sender email is invalid
+ during a "send password reset email" attempt.
+ */
+static NSString *const kInvalidSenderEmailErrorMessage = @"INVALID_SENDER";
+
+/** @var kInvalidMessagePayloadErrorMessage
+ @brief This is the error message the server will respond with if there are invalid parameters in
+ the payload during a "send password reset email" attempt.
+ */
+static NSString *const kInvalidMessagePayloadErrorMessage = @"INVALID_MESSAGE_PAYLOAD";
+
+/** @var kInvalidRecipientEmailErrorMessage
+ @brief This is the error message the server will respond with if the recipient email is invalid.
+ */
+static NSString *const kInvalidRecipientEmailErrorMessage = @"INVALID_RECIPIENT_EMAIL";
+
+/** @var kInvalidPhoneNumberErrorMessage
+ @brief This is the error message the server will respond with if an incorrectly formatted phone
+ number is provided.
+ */
+static NSString *const kInvalidPhoneNumberErrorMessage = @"INVALID_PHONE_NUMBER";
+
+/** @var kInvalidVerificationCodeErrorMessage
+ @brief This is the error message the server will respond with if an invalid verification code is
+ provided.
+ */
+static NSString *const kInvalidVerificationCodeErrorMessage = @"INVALID_CODE";
+
+/** @var kInvalidSessionInfoErrorMessage
+ @brief This is the error message the server will respond with if an invalid session info
+ (verification ID) is provided.
+ */
+static NSString *const kInvalidSessionInfoErrorMessage = @"INVALID_SESSION_INFO";
+
+/** @var kSessionExpiredErrorMessage
+ @brief This is the error message the server will respond with if the SMS code has expired before
+ it is used.
+ */
+static NSString *const kSessionExpiredErrorMessage = @"SESSION_EXPIRED";
+
+/** @var kMissingAppCredentialErrorMessage
+ @brief This is the error message the server will respond with if the APNS token is missing in a
+ verifyClient request.
+ */
+static NSString *const kMissingAppCredentialErrorMessage = @"MISSING_APP_CREDENTIAL";
+
+/** @var kMissingAppCredentialErrorMessage
+ @brief This is the error message the server will respond with if the APNS token in a
+ verifyClient request is invalid.
+ */
+static NSString *const kInvalidAppCredentialErrorMessage = @"INVALID_APP_CREDENTIAL";
+
+/** @var kQuoutaExceededErrorMessage
+ @brief This is the error message the server will respond with if the quota for SMS text messages
+ has been exceeded for the project.
+ */
+static NSString *const kQuoutaExceededErrorMessage = @"QUOTA_EXCEEDED";
+
+/** @var kAppNotVerifiedErrorMessage
+ @brief This is the error message the server will respond with if Firebase could not verify the
+ app during a phone authentication flow.
+ */
+static NSString *const kAppNotVerifiedErrorMessage = @"APP_NOT_VERIFIED";
+
+/** @var gBackendImplementation
+ @brief The singleton FIRAuthBackendImplementation instance to use.
+ */
+static id<FIRAuthBackendImplementation> gBackendImplementation;
+
+/** @class FIRAuthBackendRPCImplementation
+ @brief The default RPC-based backend implementation.
+ */
+@interface FIRAuthBackendRPCImplementation : NSObject <FIRAuthBackendImplementation>
+
+/** @property RPCIssuer
+ @brief An instance of FIRAuthBackendRPCIssuer for making RPC requests. Allows the RPC
+ requests/responses to be easily faked.
+ */
+@property(nonatomic, strong) id<FIRAuthBackendRPCIssuer> RPCIssuer;
+
+@end
+
+@implementation FIRAuthBackend
+
++ (id<FIRAuthBackendImplementation>)implementation {
+ if (!gBackendImplementation) {
+ gBackendImplementation = [[FIRAuthBackendRPCImplementation alloc] init];
+ }
+ return gBackendImplementation;
+}
+
++ (void)setBackendImplementation:(id<FIRAuthBackendImplementation>)backendImplementation {
+ gBackendImplementation = backendImplementation;
+}
+
++ (void)setDefaultBackendImplementationWithRPCIssuer:
+ (nullable id<FIRAuthBackendRPCIssuer>)RPCIssuer {
+ FIRAuthBackendRPCImplementation *defaultImplementation =
+ [[FIRAuthBackendRPCImplementation alloc] init];
+ if (RPCIssuer) {
+ defaultImplementation.RPCIssuer = RPCIssuer;
+ }
+ gBackendImplementation = defaultImplementation;
+}
+
++ (void)createAuthURI:(FIRCreateAuthURIRequest *)request
+ callback:(FIRCreateAuthURIResponseCallback)callback {
+ [[self implementation] createAuthURI:request callback:callback];
+}
+
++ (void)getAccountInfo:(FIRGetAccountInfoRequest *)request
+ callback:(FIRGetAccountInfoResponseCallback)callback {
+ [[self implementation] getAccountInfo:request callback:callback];
+}
+
++ (void)setAccountInfo:(FIRSetAccountInfoRequest *)request
+ callback:(FIRSetAccountInfoResponseCallback)callback {
+ [[self implementation] setAccountInfo:request callback:callback];
+}
+
++ (void)verifyAssertion:(FIRVerifyAssertionRequest *)request
+ callback:(FIRVerifyAssertionResponseCallback)callback {
+ [[self implementation] verifyAssertion:request callback:callback];
+}
+
++ (void)verifyCustomToken:(FIRVerifyCustomTokenRequest *)request
+ callback:(FIRVerifyCustomTokenResponseCallback)callback {
+ [[self implementation] verifyCustomToken:request callback:callback];
+}
+
++ (void)verifyPassword:(FIRVerifyPasswordRequest *)request
+ callback:(FIRVerifyPasswordResponseCallback)callback {
+ [[self implementation] verifyPassword:request callback:callback];
+}
+
++ (void)secureToken:(FIRSecureTokenRequest *)request
+ callback:(FIRSecureTokenResponseCallback)callback {
+ [[self implementation] secureToken:request callback:callback];
+}
+
++ (void)getOOBConfirmationCode:(FIRGetOOBConfirmationCodeRequest *)request
+ callback:(FIRGetOOBConfirmationCodeResponseCallback)callback {
+ [[self implementation] getOOBConfirmationCode:request callback:callback];
+}
+
++ (void)signUpNewUser:(FIRSignUpNewUserRequest *)request
+ callback:(FIRSignupNewUserCallback)callback {
+ [[self implementation] signUpNewUser:request callback:callback];
+}
+
++ (void)deleteAccount:(FIRDeleteAccountRequest *)request callback:(FIRDeleteCallBack)callback {
+ [[self implementation] deleteAccount:request callback:callback];
+}
+
++ (void)sendVerificationCode:(FIRSendVerificationCodeRequest *)request
+ callback:(FIRSendVerificationCodeResponseCallback)callback {
+ [[self implementation] sendVerificationCode:request callback:callback];
+}
+
++ (void)verifyPhoneNumber:(FIRVerifyPhoneNumberRequest *)request
+ callback:(FIRVerifyPhoneNumberResponseCallback)callback {
+ [[self implementation] verifyPhoneNumber:request callback:callback];
+}
+
++ (void)verifyClient:(id)request callback:(FIRVerifyClientResponseCallback)callback {
+ [[self implementation] verifyClient:request callback:callback];
+}
+
++ (void)resetPassword:(FIRResetPasswordRequest *)request
+ callback:(FIRResetPasswordCallback)callback {
+ [[self implementation] resetPassword:request callback:callback];
+}
+
+@end
+
+@interface FIRAuthBackendRPCIssuerImplementation : NSObject <FIRAuthBackendRPCIssuer>
+@end
+
+@implementation FIRAuthBackendRPCIssuerImplementation {
+ /** @var The session fetcher service.
+ */
+ GTMSessionFetcherService *_fetcherService;
+}
+
+- (instancetype)init {
+ self = [super init];
+ if (self) {
+ _fetcherService = [[GTMSessionFetcherService alloc] init];
+ _fetcherService.userAgent = [NSString stringWithFormat:@"FirebaseAuth.iOS/%s %@",
+ FirebaseAuthVersionString, GTMFetcherStandardUserAgentString(nil)];
+ _fetcherService.callbackQueue = FIRAuthGlobalWorkQueue();
+ }
+ return self;
+}
+
+- (void)asyncPostToURL:(NSURL *)URL
+ body:(NSData *)body
+ contentType:(NSString *)contentType
+ completionHandler:(void (^)(NSData *_Nullable, NSError *_Nullable))handler {
+ NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
+ [request setValue:contentType forHTTPHeaderField:@"Content-Type"];
+ NSString *bundleID = [[NSBundle mainBundle] bundleIdentifier];
+ [request setValue:bundleID forHTTPHeaderField:kIosBundleIdentifierHeader];
+
+ NSArray<NSString *> *preferredLocalizations = [NSBundle mainBundle].preferredLocalizations;
+ if (preferredLocalizations.count) {
+ NSString *acceptLanguage = preferredLocalizations.firstObject;
+ [request setValue:acceptLanguage forHTTPHeaderField:@"Accept-Language"];
+ }
+
+ GTMSessionFetcher* fetcher = [_fetcherService fetcherWithRequest:request];
+ fetcher.bodyData = body;
+ [fetcher beginFetchWithCompletionHandler:handler];
+}
+
+@end
+
+@implementation FIRAuthBackendRPCImplementation
+
+- (instancetype)init {
+ self = [super init];
+ if (self) {
+ _RPCIssuer = [[FIRAuthBackendRPCIssuerImplementation alloc] init];
+ }
+ return self;
+}
+
+- (void)createAuthURI:(FIRCreateAuthURIRequest *)request
+ callback:(FIRCreateAuthURIResponseCallback)callback {
+ FIRCreateAuthURIResponse *response = [[FIRCreateAuthURIResponse alloc] init];
+ [self postWithRequest:request response:response callback:^(NSError *error) {
+ if (error) {
+ callback(nil, error);
+ } else {
+ callback(response, nil);
+ }
+ }];
+}
+
+- (void)getAccountInfo:(FIRGetAccountInfoRequest *)request
+ callback:(FIRGetAccountInfoResponseCallback)callback {
+ FIRGetAccountInfoResponse *response = [[FIRGetAccountInfoResponse alloc] init];
+ [self postWithRequest:request response:response callback:^(NSError *error) {
+ if (error) {
+ callback(nil, error);
+ } else {
+ callback(response, nil);
+ }
+ }];
+}
+
+- (void)setAccountInfo:(FIRSetAccountInfoRequest *)request
+ callback:(FIRSetAccountInfoResponseCallback)callback {
+ FIRSetAccountInfoResponse *response = [[FIRSetAccountInfoResponse alloc] init];
+ [self postWithRequest:request response:response callback:^(NSError *error) {
+ if (error) {
+ callback(nil, error);
+ } else {
+ callback(response, nil);
+ }
+ }];
+}
+
+- (void)verifyAssertion:(FIRVerifyAssertionRequest *)request
+ callback:(FIRVerifyAssertionResponseCallback)callback {
+ FIRVerifyAssertionResponse *response = [[FIRVerifyAssertionResponse alloc] init];
+ [self postWithRequest:request response:response callback:^(NSError *error) {
+ if (error) {
+ callback(nil, error);
+ return;
+ }
+ callback(response, nil);
+ }];
+}
+
+- (void)verifyCustomToken:(FIRVerifyCustomTokenRequest *)request
+ callback:(FIRVerifyCustomTokenResponseCallback)callback {
+ FIRVerifyCustomTokenResponse *response = [[FIRVerifyCustomTokenResponse alloc] init];
+ [self postWithRequest:request response:response callback:^(NSError *error) {
+ if (error) {
+ callback(nil, error);
+ } else {
+ callback(response, nil);
+ }
+ }];
+}
+
+- (void)verifyPassword:(FIRVerifyPasswordRequest *)request
+ callback:(FIRVerifyPasswordResponseCallback)callback {
+ FIRVerifyPasswordResponse *response = [[FIRVerifyPasswordResponse alloc] init];
+ [self postWithRequest:request response:response callback:^(NSError *error) {
+ if (error) {
+ callback(nil, error);
+ } else {
+ callback(response, nil);
+ }
+ }];
+}
+
+- (void)secureToken:(FIRSecureTokenRequest *)request
+ callback:(FIRSecureTokenResponseCallback)callback {
+ FIRSecureTokenResponse *response = [[FIRSecureTokenResponse alloc] init];
+ [self postWithRequest:request response:response callback:^(NSError *error) {
+ if (error) {
+ callback(nil, error);
+ } else {
+ callback(response, nil);
+ }
+ }];
+}
+
+- (void)getOOBConfirmationCode:(FIRGetOOBConfirmationCodeRequest *)request
+ callback:(FIRGetOOBConfirmationCodeResponseCallback)callback {
+ FIRGetOOBConfirmationCodeResponse *response = [[FIRGetOOBConfirmationCodeResponse alloc] init];
+ [self postWithRequest:request response:response callback:^(NSError *error) {
+ if (error) {
+ callback(nil, error);
+ } else {
+ callback(response, nil);
+ }
+ }];
+}
+
+- (void)signUpNewUser:(FIRSignUpNewUserRequest *)request
+ callback:(FIRSignupNewUserCallback)callback{
+ FIRSignUpNewUserResponse *response = [[FIRSignUpNewUserResponse alloc] init];
+ [self postWithRequest:request response:response callback:^(NSError *error) {
+ if (error) {
+ callback(nil, error);
+ } else {
+ callback(response, nil);
+ }
+ }];
+}
+
+- (void)deleteAccount:(FIRDeleteAccountRequest *)request callback:(FIRDeleteCallBack)callback {
+ FIRDeleteAccountResponse *response = [[FIRDeleteAccountResponse alloc] init];
+ [self postWithRequest:request response:response callback:callback];
+}
+
+- (void)sendVerificationCode:(FIRSendVerificationCodeRequest *)request
+ callback:(FIRSendVerificationCodeResponseCallback)callback {
+ FIRSendVerificationCodeResponse *response = [[FIRSendVerificationCodeResponse alloc] init];
+ [self postWithRequest:request response:response callback:^(NSError *error) {
+ if (error) {
+ callback(nil, error);
+ } else {
+ callback(response, error);
+ }
+ }];
+}
+
+- (void)verifyPhoneNumber:(FIRVerifyPhoneNumberRequest *)request
+ callback:(FIRVerifyPhoneNumberResponseCallback)callback {
+ FIRVerifyPhoneNumberResponse *response = [[FIRVerifyPhoneNumberResponse alloc] init];
+ [self postWithRequest:request response:response callback:^(NSError *error) {
+ if (error) {
+ callback(nil, error);
+ return;
+ }
+ // Check whether or not the successful response is actually the special case phone auth flow
+ // that returns a temporary proof and phone number.
+ if (response.phoneNumber.length && response.temporaryProof.length) {
+ FIRPhoneAuthCredential *credential =
+ [[FIRPhoneAuthCredential alloc] initWithTemporaryProof:response.temporaryProof
+ phoneNumber:response.phoneNumber
+ providerID:FIRPhoneAuthProviderID];
+ callback(nil,
+ [FIRAuthErrorUtils credentialAlreadyInUseErrorWithMessage:nil
+ credential:credential]);
+ return;
+ }
+ callback(response, nil);
+ }];
+}
+
+- (void)verifyClient:(id)request callback:(FIRVerifyClientResponseCallback)callback {
+ FIRVerifyClientResponse *response = [[FIRVerifyClientResponse alloc] init];
+ [self postWithRequest:request response:response callback:^(NSError *error) {
+ if (error) {
+ callback(nil, error);
+ return;
+ }
+ callback(response, nil);
+ }];
+}
+
+- (void)resetPassword:(FIRResetPasswordRequest *)request
+ callback:(FIRResetPasswordCallback)callback {
+ FIRResetPasswordResponse *response = [[FIRResetPasswordResponse alloc] init];
+ [self postWithRequest:request response:response callback:^(NSError *error) {
+ if (error) {
+ callback(nil, error);
+ return;
+ }
+ callback(response, nil);
+ }];
+}
+
+#pragma mark - Generic RPC handling methods
+
+/** @fn postWithRequest:response:callback:
+ @brief Calls the RPC using HTTP POST.
+ @remarks Possible error responses:
+ @see FIRAuthInternalErrorCodeRPCRequestEncodingError
+ @see FIRAuthInternalErrorCodeJSONSerializationError
+ @see FIRAuthInternalErrorCodeNetworkError
+ @see FIRAuthInternalErrorCodeUnexpectedErrorResponse
+ @see FIRAuthInternalErrorCodeUnexpectedResponse
+ @see FIRAuthInternalErrorCodeRPCResponseDecodingError
+ @param request The request.
+ @param response The empty response to be filled.
+ @param callback The callback for both success and failure.
+ */
+- (void)postWithRequest:(id<FIRAuthRPCRequest>)request
+ response:(id<FIRAuthRPCResponse>)response
+ callback:(void (^)(NSError *error))callback {
+ NSError *error;
+ id postBody = [request unencodedHTTPRequestBodyWithError:&error];
+ if (!postBody) {
+ callback([FIRAuthErrorUtils RPCRequestEncodingErrorWithUnderlyingError:error]);
+ return;
+ }
+ NSJSONWritingOptions JSONWritingOptions = 0;
+ #if DEBUG
+ JSONWritingOptions |= NSJSONWritingPrettyPrinted;
+ #endif
+
+ NSData *bodyData;
+ if ([NSJSONSerialization isValidJSONObject:postBody]) {
+ bodyData = [NSJSONSerialization dataWithJSONObject:postBody
+ options:JSONWritingOptions
+ error:&error];
+ if (!bodyData) {
+ // This is an untested case. This happens exclusively when there is an error in the framework
+ // implementation of dataWithJSONObject:options:error:. This shouldn't normally occur as
+ // isValidJSONObject: should return NO in any case we should encounter an error.
+ error = [FIRAuthErrorUtils JSONSerializationErrorWithUnderlyingError:error];
+ }
+ } else {
+ error = [FIRAuthErrorUtils JSONSerializationErrorForUnencodableType];
+ }
+ if (!bodyData) {
+ callback(error);
+ return;
+ }
+
+ [_RPCIssuer asyncPostToURL:[request requestURL]
+ body:bodyData
+ contentType:kJSONContentType
+ completionHandler:^(NSData *data, NSError *error) {
+ // If there is an error with no body data at all, then this must be a network error.
+ if (error && !data) {
+ callback([FIRAuthErrorUtils networkErrorWithUnderlyingError:error]);
+ return;
+ }
+
+ // Try to decode the HTTP response data which may contain either a successful response or error
+ // message.
+ NSError *jsonError;
+ NSDictionary * dictionary =
+ [NSJSONSerialization JSONObjectWithData:data
+ options:NSJSONReadingMutableLeaves
+ error:&jsonError];
+ if (!dictionary) {
+ if (error) {
+ // We have an error, but we couldn't decode the body, so we have no additional information
+ // other than the raw response and the original NSError (the jsonError is infered by the
+ // error code (FIRAuthErrorCodeUnexpectedHTTPResponse, and is irrelevant.)
+ callback([FIRAuthErrorUtils unexpectedErrorResponseWithData:data underlyingError:error]);
+ } else {
+ // This is supposed to be a "successful" response, but we couldn't deserialize the body.
+ callback([FIRAuthErrorUtils unexpectedResponseWithData:data underlyingError:jsonError]);
+ }
+ return;
+ }
+ if (![dictionary isKindOfClass:[NSDictionary class]]) {
+ if (error) {
+ callback([FIRAuthErrorUtils unexpectedErrorResponseWithDeserializedResponse:dictionary]);
+ } else {
+ callback([FIRAuthErrorUtils unexpectedResponseWithDeserializedResponse:dictionary]);
+ }
+ return;
+ }
+
+ // At this point we either have an error with successfully decoded details in the body, or we
+ // have a response which must pass further validation before we know it's truly successful.
+ // We deal with the case where we have an error with successfully decoded error details first:
+ if (error) {
+ NSDictionary *errorDictionary = dictionary[kErrorKey];
+ if ([errorDictionary isKindOfClass:[NSDictionary class]]) {
+ id<NSObject> errorMessage = errorDictionary[kErrorMessageKey];
+ if ([errorMessage isKindOfClass:[NSString class]]) {
+ NSString *errorMessageString = (NSString *)errorMessage;
+
+ // Contruct client error.
+ NSError *clientError = [[self class] clientErrorWithServerErrorMessage:errorMessageString
+ errorDictionary:errorDictionary
+ response:response];
+ if (clientError) {
+ callback(clientError);
+ return;
+ }
+ }
+ // Not a message we know, return the message directly.
+ if (errorMessage) {
+ NSError *unexpecterErrorResponse =
+ [FIRAuthErrorUtils unexpectedErrorResponseWithDeserializedResponse:errorDictionary];
+ callback(unexpecterErrorResponse);
+ return;
+ }
+ }
+ // No error message at all, return the decoded response.
+ callback([FIRAuthErrorUtils unexpectedErrorResponseWithDeserializedResponse:dictionary]);
+ return;
+ }
+
+ // Finally, we try to populate the response object with the JSON values.
+ if (![response setWithDictionary:dictionary error:&error]) {
+ callback([FIRAuthErrorUtils RPCResponseDecodingErrorWithDeserializedResponse:dictionary
+ underlyingError:error]);
+ return;
+ }
+
+ // Success! The response object originally passed in can be used by the caller.
+ callback(nil);
+ }];
+}
+
+/** @fn clientErrorWithServerErrorMessage:errorDictionary:
+ @brief Translates known server errors to client errors.
+ @param serverErrorMessage The error message from the server.
+ @param errorDictionary The error part of the response from the server.
+ @param response The response from the server RPC.
+ @return A client error, if any.
+ */
++ (nullable NSError *)clientErrorWithServerErrorMessage:(NSString *)serverErrorMessage
+ errorDictionary:(NSDictionary *)errorDictionary
+ response:(id<FIRAuthRPCResponse>)response {
+ NSString *shortErrorMessage = serverErrorMessage;
+ NSString *serverDetailErrorMessage;
+ NSRange colonRange = [serverErrorMessage rangeOfString:@":"];
+ if (colonRange.location != NSNotFound) {
+ shortErrorMessage = [serverErrorMessage substringToIndex:colonRange.location];
+ shortErrorMessage =
+ [shortErrorMessage stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
+ serverDetailErrorMessage = [serverErrorMessage substringFromIndex:colonRange.location + 1];
+ serverDetailErrorMessage = [serverDetailErrorMessage stringByTrimmingCharactersInSet:
+ [NSCharacterSet whitespaceCharacterSet]];
+ }
+
+ // Delegate the responsibility for constructing the client error to the response object,
+ // if possible.
+ SEL clientErrorWithServerErrorMessageSelector =
+ @selector(clientErrorWithShortErrorMessage:detailErrorMessage:);
+ if ([response respondsToSelector:clientErrorWithServerErrorMessageSelector]) {
+ NSError *error = [response clientErrorWithShortErrorMessage:shortErrorMessage
+ detailErrorMessage:serverDetailErrorMessage];
+ if (error) {
+ return error;
+ }
+ }
+
+ if ([shortErrorMessage isEqualToString:kUserNotFoundErrorMessage]) {
+ return [FIRAuthErrorUtils userNotFoundErrorWithMessage:serverDetailErrorMessage];
+ }
+
+ if ([shortErrorMessage isEqualToString:kUserDeletedErrorMessage]) {
+ return [FIRAuthErrorUtils userNotFoundErrorWithMessage:serverDetailErrorMessage];
+ }
+
+ if ([shortErrorMessage isEqualToString:kInvalidLocalIDErrorMessage]) {
+ // This case shouldn't be necessary but it is for now: b/27908364 .
+ return [FIRAuthErrorUtils userNotFoundErrorWithMessage:serverDetailErrorMessage];
+ }
+
+ if ([shortErrorMessage isEqualToString:kUserTokenExpiredErrorMessage]) {
+ return [FIRAuthErrorUtils userTokenExpiredErrorWithMessage:serverDetailErrorMessage];
+ }
+
+ if ([shortErrorMessage isEqualToString:kTooManyRequestsErrorMessage]) {
+ return [FIRAuthErrorUtils tooManyRequestsErrorWithMessage:serverDetailErrorMessage];
+ }
+
+ if ([shortErrorMessage isEqualToString:kInvalidCustomTokenErrorMessage]) {
+ return [FIRAuthErrorUtils invalidCustomTokenErrorWithMessage:serverDetailErrorMessage];
+ }
+
+ if ([shortErrorMessage isEqualToString:kCustomTokenMismatch]) {
+ return [FIRAuthErrorUtils customTokenMistmatchErrorWithMessage:serverDetailErrorMessage];
+ }
+
+ if ([shortErrorMessage isEqualToString:kInvalidCredentialErrorMessage]) {
+ return [FIRAuthErrorUtils invalidCredentialErrorWithMessage:serverDetailErrorMessage];
+ }
+
+ if ([shortErrorMessage isEqualToString:kUserDisabledErrorMessage]) {
+ return [FIRAuthErrorUtils userDisabledErrorWithMessage:serverDetailErrorMessage];
+ }
+
+ if ([shortErrorMessage isEqualToString:kOperationNotAllowedErrorMessage]) {
+ return [FIRAuthErrorUtils operationNotAllowedErrorWithMessage:serverDetailErrorMessage];
+ }
+
+ if ([shortErrorMessage isEqualToString:kPasswordLoginDisabledErrorMessage]) {
+ return [FIRAuthErrorUtils operationNotAllowedErrorWithMessage:serverDetailErrorMessage];
+ }
+
+ if ([shortErrorMessage isEqualToString:kEmailAlreadyInUseErrorMessage]) {
+ return [FIRAuthErrorUtils emailAlreadyInUseErrorWithEmail:nil];
+ }
+
+ if ([shortErrorMessage isEqualToString:kInvalidEmailErrorMessage]) {
+ return [FIRAuthErrorUtils invalidEmailErrorWithMessage:serverDetailErrorMessage];
+ }
+
+ // "INVALID_IDENTIFIER" can be returned by createAuthURI RPC. Considering email addresses are
+ // currently the only identifiers, we surface the FIRAuthErrorCodeInvalidEmail error code in this
+ // case.
+ if ([shortErrorMessage isEqualToString:kInvalidIdentifierErrorMessage]) {
+ return [FIRAuthErrorUtils invalidEmailErrorWithMessage:serverDetailErrorMessage];
+ }
+
+ if ([shortErrorMessage isEqualToString:kWrongPasswordErrorMessage]) {
+ return [FIRAuthErrorUtils wrongPasswordErrorWithMessage:serverDetailErrorMessage];
+ }
+
+ if ([shortErrorMessage isEqualToString:kCredentialTooOldErrorMessage]) {
+ return [FIRAuthErrorUtils requiresRecentLoginErrorWithMessage:serverDetailErrorMessage];
+ }
+
+ if ([shortErrorMessage isEqualToString:kInvalidUserTokenErrorMessage]) {
+ return [FIRAuthErrorUtils invalidUserTokenErrorWithMessage:serverDetailErrorMessage];
+ }
+
+ if ([shortErrorMessage isEqualToString:kFederatedUserIDAlreadyLinkedMessage]) {
+ return [FIRAuthErrorUtils credentialAlreadyInUseErrorWithMessage:serverDetailErrorMessage
+ credential:nil];
+ }
+
+ if ([shortErrorMessage isEqualToString:kWeakPasswordErrorMessagePrefix]) {
+ return [FIRAuthErrorUtils weakPasswordErrorWithServerResponseReason:serverDetailErrorMessage];
+ }
+
+ if ([shortErrorMessage isEqualToString:kExpiredActionCodeErrorMessage]) {
+ return [FIRAuthErrorUtils expiredActionCodeErrorWithMessage:serverDetailErrorMessage];
+ }
+
+ if ([shortErrorMessage isEqualToString:kInvalidActionCodeErrorMessage]) {
+ return [FIRAuthErrorUtils invalidActionCodeErrorWithMessage:serverDetailErrorMessage];
+ }
+
+ if ([shortErrorMessage isEqualToString:kInvalidSenderEmailErrorMessage]) {
+ return [FIRAuthErrorUtils invalidSenderErrorWithMessage:serverDetailErrorMessage];
+ }
+
+ if ([shortErrorMessage isEqualToString:kInvalidMessagePayloadErrorMessage]) {
+ return [FIRAuthErrorUtils invalidMessagePayloadErrorWithMessage:serverDetailErrorMessage];
+ }
+
+ if ([shortErrorMessage isEqualToString:kInvalidRecipientEmailErrorMessage]) {
+ return [FIRAuthErrorUtils invalidRecipientEmailErrorWithMessage:serverDetailErrorMessage];
+ }
+
+ if ([shortErrorMessage isEqualToString:kInvalidPhoneNumberErrorMessage]) {
+ return [FIRAuthErrorUtils invalidPhoneNumberErrorWithMessage:serverDetailErrorMessage];
+ }
+
+ if ([shortErrorMessage isEqualToString:kInvalidSessionInfoErrorMessage]) {
+ return [FIRAuthErrorUtils invalidVerificationIDErrorWithMessage:serverDetailErrorMessage];
+ }
+
+ if ([shortErrorMessage isEqualToString:kInvalidVerificationCodeErrorMessage]) {
+ return [FIRAuthErrorUtils invalidVerificationCodeErrorWithMessage:serverDetailErrorMessage];
+ }
+
+ if ([shortErrorMessage isEqualToString:kSessionExpiredErrorMessage]) {
+ return [FIRAuthErrorUtils sessionExpiredErrorWithMessage:serverDetailErrorMessage];
+ }
+
+ if ([shortErrorMessage isEqualToString:kMissingAppCredentialErrorMessage]) {
+ return [FIRAuthErrorUtils missingAppCredentialWithMessage:serverDetailErrorMessage];
+ }
+
+ if ([shortErrorMessage isEqualToString:kInvalidAppCredentialErrorMessage]) {
+ return [FIRAuthErrorUtils invalidAppCredentialWithMessage:serverDetailErrorMessage];
+ }
+
+ if ([shortErrorMessage isEqualToString:kQuoutaExceededErrorMessage]) {
+ return [FIRAuthErrorUtils quotaExceededErrorWithMessage:serverErrorMessage];
+ }
+
+ if ([shortErrorMessage isEqualToString:kAppNotVerifiedErrorMessage]) {
+ return [FIRAuthErrorUtils appNotVerifiedErrorWithMessage:serverErrorMessage];
+ }
+
+ // In this case we handle an error that might be specified in the underlying errors dictionary,
+ // the error message in determined based on the @c reason key in the dictionary.
+ if (errorDictionary[kErrorsKey]) {
+ // Check for underlying error with reason = keyInvalid;
+ id underlyingErrors = errorDictionary[kErrorsKey];
+ if ([underlyingErrors isKindOfClass:[NSArray class]]) {
+ NSArray *underlyingErrorsArray = (NSArray *)underlyingErrors;
+ for (id underlyingError in underlyingErrorsArray) {
+ if ([underlyingError isKindOfClass:[NSDictionary class]]) {
+ NSDictionary *underlyingErrorDictionary = (NSDictionary *)underlyingError;
+ NSString *reason = underlyingErrorDictionary[kReasonKey];
+ if ([reason hasPrefix:kInvalidKeyReasonValue]) {
+ return [FIRAuthErrorUtils invalidAPIKeyError];
+ }
+ if ([reason isEqualToString:kAppNotAuthorizedReasonValue]) {
+ return [FIRAuthErrorUtils appNotAuthorizedError];
+ }
+ }
+ }
+ }
+ }
+ return nil;
+}
+
+@end
diff --git a/Firebase/Auth/Source/RPCs/FIRAuthRPCRequest.h b/Firebase/Auth/Source/RPCs/FIRAuthRPCRequest.h
new file mode 100644
index 0000000..ddad3cb
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRAuthRPCRequest.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @protocol FIRAuthRPCRequest
+ @brief The generic interface for an RPC request needed by @c FIRAuthBackend.
+ */
+@protocol FIRAuthRPCRequest <NSObject>
+
+/** @fn requestURL
+ @brief Gets the request's full URL.
+ */
+- (NSURL *)requestURL;
+
+/** @fn UnencodedHTTPRequestBodyWithError:
+ @brief Creates unencoded HTTP body representing the request.
+ @param error An out field for an error which occurred constructing the request.
+ @return The HTTP body data representing the request before any encoding, or nil for error.
+ */
+- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable)error;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/RPCs/FIRAuthRPCResponse.h b/Firebase/Auth/Source/RPCs/FIRAuthRPCResponse.h
new file mode 100644
index 0000000..c130f3f
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRAuthRPCResponse.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @protocol FIRAuthRPCResponse
+ @brief The generic interface for an RPC response needed by @c FIRAuthBackend.
+ */
+@protocol FIRAuthRPCResponse <NSObject>
+
+/** @fn setFieldsWithDictionary:error:
+ @brief Sets the response instance from the decoded JSON response.
+ @param dictionary The dictionary decoded from HTTP JSON response.
+ @param error An out field for an error which occurred constructing the request.
+ @return Whether the operation was successful or not.
+ */
+- (BOOL)setWithDictionary:(NSDictionary *)dictionary
+ error:(NSError *_Nullable *_Nullable)error;
+
+@optional
+
+/** @fn clientErrorWithshortErrorMessage:detailErrorMessage
+ @brief This optional method allows response classes to create client errors given a short error
+ message and a detail error message from the server.
+ @param shortErrorMessage The short error message from the server.
+ @param detailErrorMessage The detailed error message from the server.
+ @return A client error, if any.
+ */
+- (nullable NSError *)clientErrorWithShortErrorMessage:(NSString *)shortErrorMessage
+ detailErrorMessage:(NSString *)detailErrorMessage;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/RPCs/FIRCreateAuthURIRequest.h b/Firebase/Auth/Source/RPCs/FIRCreateAuthURIRequest.h
new file mode 100644
index 0000000..bb28826
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRCreateAuthURIRequest.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "FIRAuthRPCRequest.h"
+#import "FIRIdentityToolkitRequest.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @class FIRCreateAuthURIRequest
+ @brief Represents the parameters for the createAuthUri endpoint.
+ @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/createAuthUri
+ */
+@interface FIRCreateAuthURIRequest : FIRIdentityToolkitRequest <FIRAuthRPCRequest>
+
+/** @property identifier
+ @brief The email or federated ID of the user.
+ */
+@property(nonatomic, copy) NSString *identifier;
+
+/** @property continueURI
+ @brief The URI to which the IDP redirects the user after the federated login flow.
+ */
+@property(nonatomic, copy) NSString *continueURI;
+
+/** @property openIDRealm
+ @brief Optional realm for OpenID protocol. The sub string "scheme://domain:port" of the param
+ "continueUri" is used if this is not set.
+ */
+@property(nonatomic, copy, nullable) NSString *openIDRealm;
+
+/** @property providerID
+ @brief The IdP ID. For white listed IdPs it's a short domain name e.g. google.com, aol.com,
+ live.net and yahoo.com. For other OpenID IdPs it's the OP identifier.
+ */
+@property(nonatomic, copy, nullable) NSString *providerID;
+
+/** @property clientID
+ @brief The relying party OAuth client ID.
+ */
+@property(nonatomic, copy, nullable) NSString *clientID;
+
+/** @property context
+ @brief The opaque value used by the client to maintain context info between the authentication
+ request and the IDP callback.
+ */
+@property(nonatomic, copy, nullable) NSString *context;
+
+/** @property appID
+ @brief The iOS client application's bundle identifier.
+ */
+@property(nonatomic, copy, nullable) NSString *appID;
+
+/** @fn initWithEndpoint:APIKey:
+ @brief Please use initWithIdentifier:continueURI:APIKey:
+ */
+- (nullable instancetype)initWithEndpoint:(NSString *)endpoint
+ APIKey:(NSString *)APIKey NS_UNAVAILABLE;
+
+/** @fn initWithIdentifier:continueURI:APIKey:
+ @brief Designated initializer.
+ @param identifier The email or federated ID of the user.
+ @param continueURI The URI to which the IDP redirects the user after the federated login flow.
+ @param APIKey The client's API Key.
+ */
+- (nullable instancetype)initWithIdentifier:(NSString *)identifier
+ continueURI:(NSString *)continueURI
+ APIKey:(NSString *)APIKey NS_DESIGNATED_INITIALIZER;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/RPCs/FIRCreateAuthURIRequest.m b/Firebase/Auth/Source/RPCs/FIRCreateAuthURIRequest.m
new file mode 100644
index 0000000..6d2b9e9
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRCreateAuthURIRequest.m
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRCreateAuthURIRequest.h"
+
+/** @var kCreateAuthURIEndpoint
+ @brief The "createAuthUri" endpoint.
+ */
+static NSString *const kCreateAuthURIEndpoint = @"createAuthUri";
+
+/** @var kProviderIDKey
+ @brief The key for the "providerId" value in the request.
+ */
+static NSString *const kProviderIDKey = @"providerId";
+
+/** @var kIdentifierKey
+ @brief The key for the "identifier" value in the request.
+ */
+static NSString *const kIdentifierKey = @"identifier";
+
+/** @var kContinueURIKey
+ @brief The key for the "continueUri" value in the request.
+ */
+static NSString *const kContinueURIKey = @"continueUri";
+
+/** @var kOpenIDRealmKey
+ @brief The key for the "openidRealm" value in the request.
+ */
+static NSString *const kOpenIDRealmKey = @"openidRealm";
+
+/** @var kClientIDKey
+ @brief The key for the "clientId" value in the request.
+ */
+static NSString *const kClientIDKey = @"clientId";
+
+/** @var kContextKey
+ @brief The key for the "context" value in the request.
+ */
+static NSString *const kContextKey = @"context";
+
+/** @var kAppIDKey
+ @brief The key for the "appId" value in the request.
+ */
+static NSString *const kAppIDKey = @"appId";
+
+@implementation FIRCreateAuthURIRequest
+
+- (nullable instancetype)initWithIdentifier:(NSString *)identifier
+ continueURI:(NSString *)continueURI
+ APIKey:(NSString *)APIKey {
+ self = [super initWithEndpoint:kCreateAuthURIEndpoint APIKey:APIKey];
+ if (self) {
+ _identifier = [identifier copy];
+ _continueURI = [continueURI copy];
+ }
+ return self;
+}
+
+- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable)error {
+ NSMutableDictionary *postBody = [@{
+ kIdentifierKey : _identifier,
+ kContinueURIKey : _continueURI
+ } mutableCopy];
+ if (_providerID) {
+ postBody[kProviderIDKey] = _providerID;
+ }
+ if (_openIDRealm) {
+ postBody[kOpenIDRealmKey] = _openIDRealm;
+ }
+ if (_clientID) {
+ postBody[kClientIDKey] = _clientID;
+ }
+ if (_context) {
+ postBody[kContextKey] = _context;
+ }
+ if (_appID) {
+ postBody[kAppIDKey] = _appID;
+ }
+ return postBody;
+}
+
+@end
diff --git a/Firebase/Auth/Source/RPCs/FIRCreateAuthURIResponse.h b/Firebase/Auth/Source/RPCs/FIRCreateAuthURIResponse.h
new file mode 100644
index 0000000..9f6cbae
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRCreateAuthURIResponse.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "FIRAuthRPCResponse.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @class FIRCreateAuthURIResponse
+ @brief Represents the parameters for the createAuthUri endpoint.
+ @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/createAuthUri
+ */
+@interface FIRCreateAuthURIResponse : NSObject <FIRAuthRPCResponse>
+
+/** @property authUri
+ @brief The URI used by the IDP to authenticate the user.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *authURI;
+
+/** @property registered
+ @brief Whether the user is registered if the identifier is an email.
+ */
+@property(nonatomic, assign, readonly) BOOL registered;
+
+/** @property providerId
+ @brief The provider ID of the auth URI.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *providerID;
+
+/** @property forExistingProvider
+ @brief True if the authUri is for user's existing provider.
+ */
+@property(nonatomic, assign, readonly) BOOL forExistingProvider;
+
+/** @property allProviders
+ @brief A list of provider IDs the passed @c identifier could use to sign in with.
+ */
+@property(nonatomic, copy, readonly, nullable) NSArray<NSString *> *allProviders;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/RPCs/FIRCreateAuthURIResponse.m b/Firebase/Auth/Source/RPCs/FIRCreateAuthURIResponse.m
new file mode 100644
index 0000000..7a38cca
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRCreateAuthURIResponse.m
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRCreateAuthURIResponse.h"
+
+#import "../Private/FIRAuthErrorUtils.h"
+
+@implementation FIRCreateAuthURIResponse
+
+- (BOOL)setWithDictionary:(NSDictionary *)dictionary
+ error:(NSError *_Nullable *_Nullable)error {
+ _providerID = [dictionary[@"providerId"] copy];
+ _authURI = [dictionary[@"authUri"] copy];
+ _registered = [dictionary[@"registered"] boolValue];
+ _forExistingProvider = [dictionary[@"forExistingProvider"] boolValue];
+ _allProviders = [dictionary[@"allProviders"] copy];
+ return YES;
+}
+
+@end
diff --git a/Firebase/Auth/Source/RPCs/FIRDeleteAccountRequest.h b/Firebase/Auth/Source/RPCs/FIRDeleteAccountRequest.h
new file mode 100644
index 0000000..1751e54
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRDeleteAccountRequest.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "FIRAuthRPCRequest.h"
+#import "FIRIdentityToolkitRequest.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @class FIRDeleteAccountRequest
+ @brief Represents the parameters for the deleteAccount endpoint.
+ @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/deleteAccount
+ */
+@interface FIRDeleteAccountRequest : FIRIdentityToolkitRequest<FIRAuthRPCRequest>
+
+/** @fn initWithEndpoint:APIKey:
+ @brief Please use initWithAPIKey:
+ */
+- (nullable instancetype)initWithEndpoint:(NSString *)endpoint
+ APIKey:(NSString *)APIKey NS_UNAVAILABLE;
+
+/** @fn initWithAPIKey:
+ @brief Designated initializer.
+ @param APIKey The client's API Key.
+ @param localID The local ID.
+ @param accessToken The access token.
+ */
+- (nullable instancetype)initWithAPIKey:(NSString *)APIKey
+ localID:(NSString *)localID
+ accessToken:(NSString *)accessToken NS_DESIGNATED_INITIALIZER;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/RPCs/FIRDeleteAccountRequest.m b/Firebase/Auth/Source/RPCs/FIRDeleteAccountRequest.m
new file mode 100644
index 0000000..9105ba0
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRDeleteAccountRequest.m
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRDeleteAccountRequest.h"
+
+/** @var kCreateAuthURIEndpoint
+ @brief The "deleteAccount" endpoint.
+ */
+static NSString *const kDeleteAccountEndpoint = @"deleteAccount";
+
+/** @var kIDTokenKey
+ @brief The key for the "idToken" value in the request. This is actually the STS Access Token,
+ despite it's confusing (backwards compatiable) parameter name.
+ */
+static NSString *const kIDTokenKey = @"idToken";
+
+/** @var kLocalIDKey
+ @brief The key for the "localID" value in the request.
+ */
+static NSString *const kLocalIDKey = @"localId";
+
+@implementation FIRDeleteAccountRequest {
+ /** @var _accessToken
+ @brief The STS Access Token of the authenticated user.
+ */
+ NSString *_accessToken;
+
+ /** @var _localID
+ @brief The localID of the user.
+ */
+ NSString *_localID;
+}
+
+- (nullable instancetype)initWithAPIKey:(NSString *)APIKey
+ localID:(nonnull NSString *)localID
+ accessToken:(nonnull NSString *)accessToken {
+ self = [super initWithEndpoint:kDeleteAccountEndpoint APIKey:APIKey];
+ if (self) {
+ _localID = [localID copy];
+ _accessToken = [accessToken copy];
+ }
+ return self;
+}
+
+- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable)error {
+ NSMutableDictionary *postBody = [NSMutableDictionary dictionary];
+ postBody[kIDTokenKey] = _accessToken;
+ postBody[kLocalIDKey] = _localID;
+ return postBody;
+}
+
+@end
diff --git a/Firebase/Auth/Source/RPCs/FIRDeleteAccountResponse.h b/Firebase/Auth/Source/RPCs/FIRDeleteAccountResponse.h
new file mode 100644
index 0000000..59226d6
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRDeleteAccountResponse.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "FIRAuthRPCResponse.h"
+
+/** @class FIRDeleteAccountResponse
+ @brief Represents the response from the deleteAccount endpoint.
+ @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/deleteAccount
+ */
+@interface FIRDeleteAccountResponse : NSObject<FIRAuthRPCResponse>
+@end
diff --git a/Firebase/Auth/Source/RPCs/FIRDeleteAccountResponse.m b/Firebase/Auth/Source/RPCs/FIRDeleteAccountResponse.m
new file mode 100644
index 0000000..01eb0a5
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRDeleteAccountResponse.m
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRDeleteAccountResponse.h"
+
+#import "../Private/FIRAuthErrorUtils.h"
+
+@implementation FIRDeleteAccountResponse
+
+- (BOOL)setWithDictionary:(NSDictionary *)dictionary
+ error:(NSError *_Nullable *_Nullable)error {
+ return YES;
+}
+
+@end
diff --git a/Firebase/Auth/Source/RPCs/FIRGetAccountInfoRequest.h b/Firebase/Auth/Source/RPCs/FIRGetAccountInfoRequest.h
new file mode 100644
index 0000000..b45b933
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRGetAccountInfoRequest.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "FIRAuthRPCRequest.h"
+#import "FIRIdentityToolkitRequest.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @class FIRGetAccountInfoRequest
+ @brief Represents the parameters for the getAccountInfo endpoint.
+ @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/getAccountInfo
+ */
+@interface FIRGetAccountInfoRequest : FIRIdentityToolkitRequest <FIRAuthRPCRequest>
+
+/** @property accessToken
+ @brief The STS Access Token for the authenticated user.
+ */
+@property(nonatomic, copy) NSString *accessToken;
+
+/** @fn initWithEndpoint:APIKey:
+ @brief Please use initWithAPIKey:IDToken:
+ */
+- (nullable instancetype)initWithEndpoint:(NSString *)endpoint
+ APIKey:(NSString *)APIKey NS_UNAVAILABLE;
+
+/** @fn initWithAPIKey:accessToken:
+ @brief Designated initializer.
+ @param APIKey The client's API Key.
+ @param accessToken The Access Token of the authenticated user.
+ */
+- (nullable instancetype)initWithAPIKey:(NSString *)APIKey
+ accessToken:(NSString *)accessToken NS_DESIGNATED_INITIALIZER;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/RPCs/FIRGetAccountInfoRequest.m b/Firebase/Auth/Source/RPCs/FIRGetAccountInfoRequest.m
new file mode 100644
index 0000000..5c73086
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRGetAccountInfoRequest.m
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRGetAccountInfoRequest.h"
+
+/** @var kGetAccountInfoEndpoint
+ @brief The "getAccountInfo" endpoint.
+ */
+static NSString *const kGetAccountInfoEndpoint = @"getAccountInfo";
+
+/** @var kIDTokenKey
+ @brief The key for the "idToken" value in the request. This is actually the STS Access Token,
+ despite it's confusing (backwards compatiable) parameter name.
+ */
+static NSString *const kIDTokenKey = @"idToken";
+
+@implementation FIRGetAccountInfoRequest
+
+- (nullable instancetype)initWithAPIKey:(NSString *)APIKey
+ accessToken:(NSString *)accessToken {
+ self = [super initWithEndpoint:kGetAccountInfoEndpoint APIKey:APIKey];
+ if (self) {
+ _accessToken = [accessToken copy];
+ }
+ return self;
+}
+
+- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable)error {
+ return @{
+ kIDTokenKey : _accessToken
+ };
+}
+
+@end
diff --git a/Firebase/Auth/Source/RPCs/FIRGetAccountInfoResponse.h b/Firebase/Auth/Source/RPCs/FIRGetAccountInfoResponse.h
new file mode 100644
index 0000000..009f3c1
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRGetAccountInfoResponse.h
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "FIRAuthRPCResponse.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @class FIRGetAccountInfoResponseProviderUserInfo
+ @brief Represents the provider user info part of the response from the getAccountInfo endpoint.
+ @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/getAccountInfo
+ */
+@interface FIRGetAccountInfoResponseProviderUserInfo : NSObject
+
+/** @property providerID
+ @brief The ID of the identity provider.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *providerID;
+
+/** @property displayName
+ @brief The user's display name at the identity provider.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *displayName;
+
+/** @property photoURL
+ @brief The user's photo URL at the identity provider.
+ */
+@property(nonatomic, strong, readonly, nullable) NSURL *photoURL;
+
+/** @property federatedID
+ @brief The user's identifier at the identity provider.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *federatedID;
+
+/** @property email
+ @brief The user's email at the identity provider.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *email;
+
+/** @property phoneNumber
+ @brief A phone number associated with the user.
+ */
+@property(nonatomic, readonly, nullable) NSString *phoneNumber;
+
+/** @fn init
+ @brief Please use initWithDictionary:
+ */
+- (instancetype)init NS_UNAVAILABLE;
+
+/** @fn initWithAPIKey:
+ @brief Designated initializer.
+ @param dictionary The provider user info data from endpoint.
+ */
+- (instancetype)initWithDictionary:(NSDictionary *)dictionary NS_DESIGNATED_INITIALIZER;
+
+@end
+
+/** @class FIRGetAccountInfoResponseUser
+ @brief Represents the firebase user info part of the response from the getAccountInfo endpoint.
+ @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/getAccountInfo
+ */
+@interface FIRGetAccountInfoResponseUser : NSObject
+
+/** @property localID
+ @brief The ID of the user.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *localID;
+
+/** @property email
+ @brief The email or the user.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *email;
+
+/** @property emailVerified
+ @brief Whether the email has been verified.
+ */
+@property(nonatomic, assign, readonly) BOOL emailVerified;
+
+/** @property displayName
+ @brief The display name of the user.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *displayName;
+
+/** @property photoURL
+ @brief The user's photo URL.
+ */
+@property(nonatomic, strong, readonly, nullable) NSURL *photoURL;
+
+/** @property providerUserInfo
+ @brief The user's profiles at the associated identity providers.
+ */
+@property(nonatomic, strong, readonly, nullable)
+ NSArray<FIRGetAccountInfoResponseProviderUserInfo *> *providerUserInfo;
+
+/** @property passwordHash
+ @brief Information about user's password.
+ @remarks This is not necessarily the hash of user's actual password.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *passwordHash;
+
+/** @property phoneNumber
+ @brief A phone number associated with the user.
+ */
+@property(nonatomic, readonly, nullable) NSString *phoneNumber;
+
+/** @fn init
+ @brief Please use initWithDictionary:
+ */
+- (instancetype)init NS_UNAVAILABLE;
+
+/** @fn initWithAPIKey:
+ @brief Designated initializer.
+ @param dictionary The provider user info data from endpoint.
+ */
+- (instancetype)initWithDictionary:(NSDictionary *)dictionary NS_DESIGNATED_INITIALIZER;
+
+@end
+
+/** @class FIRGetAccountInfoResponse
+ @brief Represents the response from the setAccountInfo endpoint.
+ @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/getAccountInfo
+ */
+@interface FIRGetAccountInfoResponse : NSObject <FIRAuthRPCResponse>
+
+/** @property providerUserInfo
+ @brief The requested users' profiles.
+ */
+@property(nonatomic, strong, readonly, nullable) NSArray<FIRGetAccountInfoResponseUser *> *users;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/RPCs/FIRGetAccountInfoResponse.m b/Firebase/Auth/Source/RPCs/FIRGetAccountInfoResponse.m
new file mode 100644
index 0000000..ba10746
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRGetAccountInfoResponse.m
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRGetAccountInfoResponse.h"
+
+#import "../Private/FIRAuthErrorUtils.h"
+
+/** @var kErrorKey
+ @brief The key for the "error" value in JSON responses from the server.
+ */
+static NSString *const kErrorKey = @"error";
+
+@implementation FIRGetAccountInfoResponseProviderUserInfo
+
+- (instancetype)initWithDictionary:(NSDictionary *)dictionary {
+ self = [super init];
+ if (self) {
+ _providerID = [dictionary[@"providerId"] copy];
+ _displayName = [dictionary[@"displayName"] copy];
+ NSString *photoURL = dictionary[@"photoUrl"];
+ if (photoURL) {
+ _photoURL = [NSURL URLWithString:photoURL];
+ }
+ _federatedID = [dictionary[@"federatedId"] copy];
+ _email = [dictionary[@"email"] copy];
+ _phoneNumber = [dictionary[@"phoneNumber"] copy];
+ }
+ return self;
+}
+
+@end
+
+@implementation FIRGetAccountInfoResponseUser
+
+- (instancetype)initWithDictionary:(NSDictionary *)dictionary {
+ self = [super init];
+ if (self) {
+ NSArray<NSDictionary *> *providerUserInfoData = dictionary[@"providerUserInfo"];
+ if (providerUserInfoData) {
+ NSMutableArray<FIRGetAccountInfoResponseProviderUserInfo *> *providerUserInfoArray =
+ [NSMutableArray arrayWithCapacity:providerUserInfoData.count];
+ for (NSDictionary *dictionary in providerUserInfoData) {
+ [providerUserInfoArray addObject:
+ [[FIRGetAccountInfoResponseProviderUserInfo alloc] initWithDictionary:dictionary]];
+ }
+ _providerUserInfo = [providerUserInfoArray copy];
+ }
+ _localID = [dictionary[@"localId"] copy];
+ _displayName = [dictionary[@"displayName"] copy];
+ _email = [dictionary[@"email"] copy];
+ NSString *photoURL = dictionary[@"photoUrl"];
+ if (photoURL) {
+ _photoURL = [NSURL URLWithString:photoURL];
+ }
+ _emailVerified = [dictionary[@"emailVerified"] boolValue];
+ _passwordHash = [dictionary[@"passwordHash"] copy];
+ _phoneNumber = [dictionary[@"phoneNumber"] copy];
+ }
+ return self;
+}
+
+@end
+
+@implementation FIRGetAccountInfoResponse
+
+- (BOOL)setWithDictionary:(NSDictionary *)dictionary
+ error:(NSError *_Nullable *_Nullable)error {
+ NSArray<NSDictionary *> *usersData = dictionary[@"users"];
+ // The client side never sends a getAccountInfo request with multiple localID, so only one user
+ // data is expected in the response.
+ if (![usersData isKindOfClass:[NSArray class]] || usersData.count != 1) {
+ if (error) {
+ *error = [FIRAuthErrorUtils unexpectedResponseWithDeserializedResponse:dictionary];
+ }
+ return NO;
+ }
+ _users = @[ [[FIRGetAccountInfoResponseUser alloc] initWithDictionary:usersData.firstObject] ];
+ return YES;
+}
+
+@end
diff --git a/Firebase/Auth/Source/RPCs/FIRGetOOBConfirmationCodeRequest.h b/Firebase/Auth/Source/RPCs/FIRGetOOBConfirmationCodeRequest.h
new file mode 100644
index 0000000..08ab495
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRGetOOBConfirmationCodeRequest.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "FIRAuthRPCRequest.h"
+#import "FIRIdentityToolkitRequest.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @enum FIRGetOOBConfirmationCodeRequestType
+ @brief Types of OOB Confirmation Code requests.
+ */
+typedef NS_ENUM(NSInteger, FIRGetOOBConfirmationCodeRequestType) {
+ /** @var FIRGetOOBConfirmationCodeRequestTypePasswordReset
+ @brief Requests a password reset code.
+ */
+ FIRGetOOBConfirmationCodeRequestTypePasswordReset,
+
+ /** @var FIRGetOOBConfirmationCodeRequestTypeVerifyEmail
+ @brief Requests an email verification code.
+ */
+ FIRGetOOBConfirmationCodeRequestTypeVerifyEmail,
+};
+
+/** @enum FIRGetOOBConfirmationCodeRequest
+ @brief Represents the parameters for the getOOBConfirmationCode endpoint.
+ */
+@interface FIRGetOOBConfirmationCodeRequest : FIRIdentityToolkitRequest <FIRAuthRPCRequest>
+
+/** @property requestType
+ @brief The types of OOB Confirmation Code to request.
+ */
+@property(nonatomic, assign, readonly) FIRGetOOBConfirmationCodeRequestType requestType;
+
+/** @property email
+ @brief The email of the user.
+ @remarks For password reset.
+ */
+@property(nonatomic, copy, nullable, readonly) NSString *email;
+
+/** @property accessToken
+ @brief The STS Access Token of the authenticated user.
+ @remarks For email change.
+ */
+@property(nonatomic, copy, nullable, readonly) NSString *accessToken;
+
+/** @fn passwordResetRequestWithEmail:APIKey:
+ @brief Creates a password reset request.
+ @param email The user's email address.
+ @param APIKey The client's API Key.
+ @return A password reset request.
+ */
++ (nullable FIRGetOOBConfirmationCodeRequest *)passwordResetRequestWithEmail:(NSString *)email
+ APIKey:(NSString *)APIKey;
+
+/** @fn verifyEmailRequestWithAccessToken:APIKey:
+ @brief Creates a password reset request.
+ @param accessToken The user's STS Access Token.
+ @param APIKey The client's API Key.
+ @return A password reset request.
+ */
++ (nullable FIRGetOOBConfirmationCodeRequest *)
+ verifyEmailRequestWithAccessToken:(NSString *)accessToken APIKey:(NSString *)APIKey;
+
+/** @fn init
+ @brief Please use a factory method.
+ */
+- (nullable instancetype)initWithEndpoint:(NSString *)endpoint
+ APIKey:(NSString *)APIKey NS_UNAVAILABLE;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/RPCs/FIRGetOOBConfirmationCodeRequest.m b/Firebase/Auth/Source/RPCs/FIRGetOOBConfirmationCodeRequest.m
new file mode 100644
index 0000000..b0523e4
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRGetOOBConfirmationCodeRequest.m
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRGetOOBConfirmationCodeRequest.h"
+
+#import "../Private/FIRAuthErrorUtils.h"
+#import "../Private/FIRAuth_Internal.h"
+
+/** @var kEndpoint
+ @brief The getOobConfirmationCode endpoint name.
+ */
+static NSString *const kEndpoint = @"getOobConfirmationCode";
+
+/** @var kRequestTypeKey
+ @brief The name of the required "requestType" property in the request.
+ */
+static NSString *const kRequestTypeKey = @"requestType";
+
+/** @var kEmailKey
+ @brief The name of the "email" property in the request.
+ */
+static NSString *const kEmailKey = @"email";
+
+/** @var kIDTokenKey
+ @brief The key for the "idToken" value in the request. This is actually the STS Access Token,
+ despite it's confusing (backwards compatiable) parameter name.
+ */
+static NSString *const kIDTokenKey = @"idToken";
+
+/** @var kPasswordResetRequestTypeValue
+ @brief The value for the "PASSWORD_RESET" request type.
+ */
+static NSString *const kPasswordResetRequestTypeValue = @"PASSWORD_RESET";
+
+/** @var kVerifyEmailRequestTypeValue
+ @brief The value for the "VERIFY_EMAIL" request type.
+ */
+static NSString *const kVerifyEmailRequestTypeValue = @"VERIFY_EMAIL";
+
+@interface FIRGetOOBConfirmationCodeRequest ()
+
+/** @fn initWithRequestType:email:APIKey:
+ @brief Designated initializer.
+ @param requestType The types of OOB Confirmation Code to request.
+ @param email The email of the user.
+ @param accessToken The STS Access Token of the currently signed in user.
+ @param APIKey The client's API Key.
+ */
+- (nullable instancetype)initWithRequestType:(FIRGetOOBConfirmationCodeRequestType)requestType
+ email:(nullable NSString *)email
+ accessToken:(nullable NSString *)accessToken
+ APIKey:(nullable NSString *)APIKey
+ NS_DESIGNATED_INITIALIZER;
+
+@end
+
+@implementation FIRGetOOBConfirmationCodeRequest
+
+/** @var requestTypeStringValueForRequestType:
+ @brief Returns the string equivilent for an @c FIRGetOOBConfirmationCodeRequestType value.
+ */
++ (NSString *)requestTypeStringValueForRequestType:
+ (FIRGetOOBConfirmationCodeRequestType)requestType {
+ switch (requestType) {
+ case FIRGetOOBConfirmationCodeRequestTypePasswordReset:
+ return kPasswordResetRequestTypeValue;
+ case FIRGetOOBConfirmationCodeRequestTypeVerifyEmail:
+ return kVerifyEmailRequestTypeValue;
+ // No default case so that we get a compiler warning if a new value was added to the enum.
+ }
+}
+
++ (FIRGetOOBConfirmationCodeRequest *)passwordResetRequestWithEmail:(NSString *)email
+ APIKey:(NSString *)APIKey {
+ return [[self alloc] initWithRequestType:FIRGetOOBConfirmationCodeRequestTypePasswordReset
+ email:email
+ accessToken:nil
+ APIKey:APIKey];
+}
+
++ (FIRGetOOBConfirmationCodeRequest *)
+ verifyEmailRequestWithAccessToken:(NSString *)accessToken APIKey:(NSString *)APIKey {
+ return [[self alloc] initWithRequestType:FIRGetOOBConfirmationCodeRequestTypeVerifyEmail
+ email:nil
+ accessToken:accessToken
+ APIKey:APIKey];
+}
+
+- (nullable instancetype)initWithRequestType:(FIRGetOOBConfirmationCodeRequestType)requestType
+ email:(nullable NSString *)email
+ accessToken:(nullable NSString *)accessToken
+ APIKey:(nullable NSString *)APIKey {
+ self = [super initWithEndpoint:kEndpoint APIKey:APIKey];
+ if (self) {
+ _requestType = requestType;
+ _email = email;
+ _accessToken = accessToken;
+ }
+ return self;
+}
+
+- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable)error {
+ NSMutableDictionary *body = [@{
+ kRequestTypeKey : [[self class] requestTypeStringValueForRequestType:_requestType]
+ } mutableCopy];
+
+ // For password reset requests, we only need an email address in addition to the already required
+ // fields.
+ if (_requestType == FIRGetOOBConfirmationCodeRequestTypePasswordReset) {
+ body[kEmailKey] = _email;
+ }
+
+ // For verify email requests, we only need an STS Access Token in addition to the already required
+ // fields.
+ if (_requestType == FIRGetOOBConfirmationCodeRequestTypeVerifyEmail) {
+ body[kIDTokenKey] = _accessToken;
+ }
+
+ return body;
+}
+
+@end
diff --git a/Firebase/Auth/Source/RPCs/FIRGetOOBConfirmationCodeResponse.h b/Firebase/Auth/Source/RPCs/FIRGetOOBConfirmationCodeResponse.h
new file mode 100644
index 0000000..69aa458
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRGetOOBConfirmationCodeResponse.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "FIRAuthRPCResponse.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @class FIRGetOOBConfirmationCodeResponse
+ @brief Represents the response from the getOobConfirmationCode endpoint.
+ */
+@interface FIRGetOOBConfirmationCodeResponse : NSObject <FIRAuthRPCResponse>
+
+/** @property OOBCode
+ @brief The OOB code returned by the server in some cases.
+ */
+@property(nonatomic, copy, readonly, nullable) NSString *OOBCode;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/RPCs/FIRGetOOBConfirmationCodeResponse.m b/Firebase/Auth/Source/RPCs/FIRGetOOBConfirmationCodeResponse.m
new file mode 100644
index 0000000..d5fc1dd
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRGetOOBConfirmationCodeResponse.m
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRGetOOBConfirmationCodeResponse.h"
+
+#import "../Private/FIRAuthErrorUtils.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @var kOOBCodeKey
+ @brief The name of the field in the response JSON for the OOB code.
+ */
+static NSString *const kOOBCodeKey = @"oobCode";
+
+@implementation FIRGetOOBConfirmationCodeResponse
+
+- (BOOL)setWithDictionary:(NSDictionary *)dictionary
+ error:(NSError *_Nullable *_Nullable)error {
+ _OOBCode = [dictionary[kOOBCodeKey] copy];
+ return YES;
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/RPCs/FIRIdentityToolkitRequest.h b/Firebase/Auth/Source/RPCs/FIRIdentityToolkitRequest.h
new file mode 100644
index 0000000..873788d
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRIdentityToolkitRequest.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @class FIRIdentityToolkitRequest
+ @brief Represents a request to an identity toolkit endpoint.
+ */
+@interface FIRIdentityToolkitRequest : NSObject
+
+/** @property endpoint
+ @brief Gets the RPC's endpoint.
+ */
+@property(nonatomic, copy, readonly) NSString *endpoint;
+
+/** @property APIKey
+ @brief Gets the client's API key used for the request.
+ */
+@property(nonatomic, copy, readonly) NSString *APIKey;
+
+/** @fn init
+ @brief Please use initWithEndpoint:APIKey:
+ */
+- (instancetype)init NS_UNAVAILABLE;
+
+/** @fn initWithEndpoint:APIKey:
+ @brief Designated initializer.
+ @param endpoint The endpoint name.
+ @param APIKey The client's API Key.
+ */
+- (nullable instancetype)initWithEndpoint:(NSString *)endpoint
+ APIKey:(NSString *)APIKey
+ NS_DESIGNATED_INITIALIZER;
+
+/** @fn requestURL
+ @brief Gets the request's full URL.
+ */
+- (NSURL *)requestURL;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/RPCs/FIRIdentityToolkitRequest.m b/Firebase/Auth/Source/RPCs/FIRIdentityToolkitRequest.m
new file mode 100644
index 0000000..fb51a82
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRIdentityToolkitRequest.m
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRIdentityToolkitRequest.h"
+
+/** @var kAPIURLFormat
+ @brief URL format for server API calls.
+ */
+static NSString *const kAPIURLFormat = @"https://%@/identitytoolkit/v3/relyingparty/%@?key=%@";
+
+/** @var gAPIHost
+ @brief Host for server API calls.
+ */
+static NSString *gAPIHost = @"www.googleapis.com";
+
+@implementation FIRIdentityToolkitRequest
+
+- (nullable instancetype)initWithEndpoint:(NSString *)endpoint
+ APIKey:(NSString *)APIKey {
+ self = [super init];
+ if (self) {
+ _endpoint = [endpoint copy];
+ _APIKey = [APIKey copy];
+ }
+ return self;
+}
+
+- (NSURL *)requestURL {
+ NSString *URLString = [NSString stringWithFormat:kAPIURLFormat, gAPIHost, _endpoint, _APIKey];
+ NSURL *URL = [NSURL URLWithString:URLString];
+ return URL;
+}
+
+#pragma mark - Internal API for development
+
++ (NSString *)host {
+ return gAPIHost;
+}
+
++ (void)setHost:(NSString *)host {
+ gAPIHost = host;
+}
+
+@end
diff --git a/Firebase/Auth/Source/RPCs/FIRResetPasswordRequest.h b/Firebase/Auth/Source/RPCs/FIRResetPasswordRequest.h
new file mode 100644
index 0000000..66b03ad
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRResetPasswordRequest.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "FIRAuthRPCRequest.h"
+#import "FIRIdentityToolkitRequest.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface FIRResetPasswordRequest : FIRIdentityToolkitRequest <FIRAuthRPCRequest>
+
+/** @property oobCode
+ @brief The oobCode sent in the request.
+ */
+@property(nonatomic, copy, readonly) NSString *oobCode;
+
+/** @property updatedPassword
+ @brief The new password sent in the request.
+ */
+@property(nonatomic, copy, readonly) NSString *updatedPassword;
+
+/** @fn initWithEndpoint:APIKey:
+ @brief Please use initWithOOBCode:oobCode: instead.
+ */
+- (nullable instancetype)initWithEndpoint:(NSString *)endpoint
+ APIKey:(NSString *)APIKey NS_UNAVAILABLE;
+
+/** @fn initWithAPIKey:oobCode:currentPassword:
+ @brief Designated initializer.
+ @param APIKey The client's API Key.
+ @param oobCode The OOB Code.
+ @param newPassword The new password.
+ */
+- (nullable instancetype)initWithAPIKey:(NSString *)APIKey
+ oobCode:(NSString *)oobCode
+ newPassword:(nullable NSString *)newPassword NS_DESIGNATED_INITIALIZER;
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/RPCs/FIRResetPasswordRequest.m b/Firebase/Auth/Source/RPCs/FIRResetPasswordRequest.m
new file mode 100644
index 0000000..603aa00
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRResetPasswordRequest.m
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRResetPasswordRequest.h"
+
+/** @var kResetPasswordEndpoint
+ @brief The "resetPassword" endpoint.
+ */
+static NSString *const kResetPasswordEndpoint = @"resetPassword";
+
+/** @var kOOBCodeKey
+ @brief The "resetPassword" key.
+ */
+static NSString *const kOOBCodeKey = @"oobCode";
+
+/** @var kCurrentPasswordKey
+ @brief The "newPassword" key.
+ */
+static NSString *const kCurrentPasswordKey = @"newPassword";
+
+@implementation FIRResetPasswordRequest
+
+- (instancetype)initWithAPIKey:(NSString *)APIKey
+ oobCode:(NSString *)oobCode
+ newPassword:(NSString *)newPassword {
+ self = [super initWithEndpoint:kResetPasswordEndpoint APIKey:APIKey];
+ if (self) {
+ _oobCode = oobCode;
+ _updatedPassword = newPassword;
+ }
+ return self;
+}
+
+- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable)error {
+ NSMutableDictionary *postBody = [NSMutableDictionary dictionary];
+ postBody[kOOBCodeKey] = _oobCode;
+ if (_updatedPassword) {
+ postBody[kCurrentPasswordKey] = _updatedPassword;
+ }
+ return postBody;
+}
+
+@end
diff --git a/Firebase/Auth/Source/RPCs/FIRResetPasswordResponse.h b/Firebase/Auth/Source/RPCs/FIRResetPasswordResponse.h
new file mode 100644
index 0000000..28eb5f4
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRResetPasswordResponse.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "FIRAuthRPCResponse.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @class FIRAuthResetPasswordResponse
+ @brief Represents the response from the resetPassword endpoint.
+ @remarks Possible error codes:
+ - FIRAuthErrorCodeWeakPassword
+ - FIRAuthErrorCodeUserDisabled
+ - FIRAuthErrorCodeOperationNotAllowed
+ - FIRAuthErrorCodeExpiredActionCode
+ - FIRAuthErrorCodeInvalidActionCode
+ @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/resetPassword
+ */
+@interface FIRResetPasswordResponse : NSObject<FIRAuthRPCResponse>
+
+/** @property email
+ @brief The email address corresponding to the reset password request.
+ */
+@property(nonatomic, strong, readonly) NSString *email;
+
+/** @property verifiedEmail
+ @brief The verified email returned from the backend.
+ */
+@property(nonatomic, strong, readonly) NSString *verifiedEmail;
+
+/** @property requestType
+ @brief The tpye of request as returned by the backend.
+ */
+@property(nonatomic, strong, readonly) NSString *requestType;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/RPCs/FIRResetPasswordResponse.m b/Firebase/Auth/Source/RPCs/FIRResetPasswordResponse.m
new file mode 100644
index 0000000..d306f6c
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRResetPasswordResponse.m
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRResetPasswordResponse.h"
+
+#import "../Private/FIRAuthErrorUtils.h"
+
+@implementation FIRResetPasswordResponse
+
+- (BOOL)setWithDictionary:(NSDictionary *)dictionary
+ error:(NSError *_Nullable *_Nullable)error {
+ _email = [dictionary[@"email"] copy];
+ _requestType = [dictionary[@"requestType"] copy];
+ _verifiedEmail = [dictionary[@"newEmail"] copy];
+ return YES;
+}
+
+@end
diff --git a/Firebase/Auth/Source/RPCs/FIRSecureTokenRequest.h b/Firebase/Auth/Source/RPCs/FIRSecureTokenRequest.h
new file mode 100644
index 0000000..44c16b1
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRSecureTokenRequest.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "FIRAuthRPCRequest.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @enum FIRSecureTokenRequestGrantType
+ @brief Represents the possible grant types for a token request.
+ */
+typedef NS_ENUM(NSUInteger, FIRSecureTokenRequestGrantType) {
+ /** @var FIRSecureTokenRequestGrantTypeAuthorizationCode
+ @brief Indicates an authorization code request.
+ @remarks Exchanges a Gitkit "ID Token" for an STS Access Token and Refresh Token.
+ */
+ FIRSecureTokenRequestGrantTypeAuthorizationCode,
+
+ /** @var FIRSecureTokenRequestGrantTypeRefreshToken
+ @brief Indicates an refresh token request.
+ @remarks Uses an existing Refresh Token to create a new Access Token.
+ */
+ FIRSecureTokenRequestGrantTypeRefreshToken,
+};
+
+/** @class FIRSecureTokenRequest
+ @brief Represents the parameters for the token endpoint.
+ */
+@interface FIRSecureTokenRequest : NSObject <FIRAuthRPCRequest>
+
+/** @property grantType
+ @brief The type of grant requested.
+ @see FIRSecureTokenRequestGrantType
+ */
+@property(nonatomic, assign, readonly) FIRSecureTokenRequestGrantType grantType;
+
+/** @property scope
+ @brief The scopes requested (a comma-delimited list of scope strings.)
+ */
+@property(nonatomic, copy, readonly, nullable) NSString *scope;
+
+/** @property refreshToken
+ @brief The client's refresh token.
+ */
+@property(nonatomic, copy, readonly, nullable) NSString *refreshToken;
+
+/** @property code
+ @brief The client's authorization code (legacy Gitkit "ID Token").
+ */
+@property(nonatomic, copy, readonly, nullable) NSString *code;
+
+/** @property APIKey
+ @brief The client's API Key.
+ */
+@property(nonatomic, copy, readonly) NSString *APIKey;
+
+/** @fn authCodeRequestWithCode:
+ @brief Creates an authorization code request with the given code (legacy Gitkit "ID Token").
+ @param code The authorization code (legacy Gitkit "ID Token").
+ @param APIKey The client's API Key.
+ @return An authorization request.
+ */
++ (FIRSecureTokenRequest *)authCodeRequestWithCode:(NSString *)code APIKey:(NSString *)APIKey;
+
+/** @fn refreshRequestWithCode:
+ @brief Creates a refresh request with the given refresh token.
+ @param refreshToken The refresh token.
+ @param APIKey The client's API Key.
+ @return A refresh request.
+ */
++ (FIRSecureTokenRequest *)refreshRequestWithRefreshToken:(NSString *)refreshToken
+ APIKey:(NSString *)APIKey;
+
+/** @fn init
+ @brief Please use initWithGrantType:scope:refreshToken:code:
+ */
+- (instancetype)init NS_UNAVAILABLE;
+
+/** @fn initWithGrantType:scope:refreshToken:code:APIKey:
+ @brief Designated initializer.
+ @param grantType The type of request.
+ @param scope The scopes requested.
+ @param refreshToken The client's refresh token (for refresh requests.)
+ @param code The client's authorization code (Gitkit ID Token) (for authorization code requests.)
+ @param APIKey The client's API Key.
+ */
+- (nullable instancetype)initWithGrantType:(FIRSecureTokenRequestGrantType)grantType
+ scope:(nullable NSString *)scope
+ refreshToken:(nullable NSString *)refreshToken
+ code:(nullable NSString *)code
+ APIKey:(NSString *)APIKey NS_DESIGNATED_INITIALIZER;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/RPCs/FIRSecureTokenRequest.m b/Firebase/Auth/Source/RPCs/FIRSecureTokenRequest.m
new file mode 100644
index 0000000..1983542
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRSecureTokenRequest.m
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRSecureTokenRequest.h"
+
+/** @var kFIRSecureTokenServiceGetTokenURLFormat
+ @brief The format of the secure token service URLs. Requires string format substitution with
+ the client's API Key.
+ */
+static NSString *const kFIRSecureTokenServiceGetTokenURLFormat = @"https://%@/v1/token?key=%@";
+
+/** @var kFIRSecureTokenServiceGrantTypeRefreshToken
+ @brief The string value of the @c FIRSecureTokenRequestGrantTypeRefreshToken request type.
+ */
+static NSString *const kFIRSecureTokenServiceGrantTypeRefreshToken = @"refresh_token";
+
+/** @var kFIRSecureTokenServiceGrantTypeAuthorizationCode
+ @brief The string value of the @c FIRSecureTokenRequestGrantTypeAuthorizationCode request type.
+ */
+static NSString *const kFIRSecureTokenServiceGrantTypeAuthorizationCode = @"authorization_code";
+
+/** @var kGrantTypeKey
+ @brief The key for the "grantType" parameter in the request.
+ */
+static NSString *const kGrantTypeKey = @"grantType";
+
+/** @var kScopeKey
+ @brief The key for the "scope" parameter in the request.
+ */
+static NSString *const kScopeKey = @"scope";
+
+/** @var kRefreshTokenKey
+ @brief The key for the "refreshToken" parameter in the request.
+ */
+static NSString *const kRefreshTokenKey = @"refreshToken";
+
+/** @var kCodeKey
+ @brief The key for the "code" parameter in the request.
+ */
+static NSString *const kCodeKey = @"code";
+
+/** @var gAPIHost
+ @brief Host for server API calls.
+ */
+static NSString *gAPIHost = @"securetoken.googleapis.com";
+
+@implementation FIRSecureTokenRequest
+
++ (FIRSecureTokenRequest *)authCodeRequestWithCode:(NSString *)code APIKey:(NSString *)APIKey {
+ return [[self alloc] initWithGrantType:FIRSecureTokenRequestGrantTypeAuthorizationCode
+ scope:nil
+ refreshToken:nil
+ code:code
+ APIKey:APIKey];
+}
+
++ (FIRSecureTokenRequest *)refreshRequestWithRefreshToken:(NSString *)refreshToken
+ APIKey:(NSString *)APIKey {
+ return [[self alloc] initWithGrantType:FIRSecureTokenRequestGrantTypeRefreshToken
+ scope:nil
+ refreshToken:refreshToken
+ code:nil
+ APIKey:APIKey];
+}
+
+/** @fn grantTypeStringWithGrantType:
+ @brief Converts a @c FIRSecureTokenRequestGrantType to it's @c NSString equivilent.
+ */
++ (NSString *)grantTypeStringWithGrantType:(FIRSecureTokenRequestGrantType)grantType {
+ switch (grantType) {
+ case FIRSecureTokenRequestGrantTypeAuthorizationCode:
+ return kFIRSecureTokenServiceGrantTypeAuthorizationCode;
+ case FIRSecureTokenRequestGrantTypeRefreshToken:
+ return kFIRSecureTokenServiceGrantTypeRefreshToken;
+ // No Default case so we will notice if new grant types are added to the enum.
+ }
+}
+
+- (nullable instancetype)initWithGrantType:(FIRSecureTokenRequestGrantType)grantType
+ scope:(nullable NSString *)scope
+ refreshToken:(nullable NSString *)refreshToken
+ code:(nullable NSString *)code
+ APIKey:(NSString *)APIKey {
+ self = [super init];
+ if (self) {
+ _grantType = grantType;
+ _scope = [scope copy];
+ _refreshToken = [refreshToken copy];
+ _code = [code copy];
+ _APIKey = [APIKey copy];
+ }
+ return self;
+}
+
+- (NSURL *)requestURL {
+ NSString *URLString =
+ [NSString stringWithFormat:kFIRSecureTokenServiceGetTokenURLFormat, gAPIHost, _APIKey];
+ NSURL *URL = [NSURL URLWithString:URLString];
+ return URL;
+}
+
+- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable)error {
+ NSMutableDictionary *postBody = [@{
+ kGrantTypeKey : [[self class] grantTypeStringWithGrantType:_grantType]
+ } mutableCopy];
+ if (_scope) {
+ postBody[kScopeKey] = _scope;
+ }
+ if (_refreshToken) {
+ postBody[kRefreshTokenKey] = _refreshToken;
+ }
+ if (_code) {
+ postBody[kCodeKey] = _code;
+ }
+ return postBody;
+}
+
+#pragma mark - Internal API for development
+
++ (NSString *)host {
+ return gAPIHost;
+}
+
++ (void)setHost:(NSString *)host {
+ gAPIHost = host;
+}
+
+@end
diff --git a/Firebase/Auth/Source/RPCs/FIRSecureTokenResponse.h b/Firebase/Auth/Source/RPCs/FIRSecureTokenResponse.h
new file mode 100644
index 0000000..0dd4a20
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRSecureTokenResponse.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "FIRAuthRPCResponse.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @class FIRSecureTokenResponse
+ @brief Represents the response from the token endpoint.
+ */
+@interface FIRSecureTokenResponse : NSObject <FIRAuthRPCResponse>
+
+/** @property approximateExpirationDate
+ @brief The approximate expiration date of the access token.
+ */
+@property(nonatomic, copy, readonly, nullable) NSDate *approximateExpirationDate;
+
+/** @property refreshToken
+ @brief The refresh token. (Possibly an updated one for refresh requests.)
+ */
+@property(nonatomic, copy, readonly, nullable) NSString *refreshToken;
+
+/** @property accessToken
+ @brief The new access token.
+ */
+@property(nonatomic, copy, readonly, nullable) NSString *accessToken;
+
+/** @property IDToken
+ @brief The new ID Token.
+ */
+@property(nonatomic, copy, readonly, nullable) NSString *IDToken;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/RPCs/FIRSecureTokenResponse.m b/Firebase/Auth/Source/RPCs/FIRSecureTokenResponse.m
new file mode 100644
index 0000000..8ff3dde
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRSecureTokenResponse.m
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRSecureTokenResponse.h"
+
+#import "../Private/FIRAuthErrorUtils.h"
+
+/** @var kExpiresInKey
+ @brief The key for the number of seconds till the access token expires.
+ */
+static NSString *const kExpiresInKey = @"expires_in";
+
+/** @var kRefreshTokenKey
+ @brief The key for the refresh token.
+ */
+static NSString *const kRefreshTokenKey = @"refresh_token";
+
+/** @var kAccessTokenKey
+ @brief The key for the access token.
+ */
+static NSString *const kAccessTokenKey = @"access_token";
+
+/** @var kIDTokenKey
+ @brief The key for the "id_token" value in the response.
+ */
+static NSString *const kIDTokenKey = @"id_token";
+
+@implementation FIRSecureTokenResponse
+
+- (nullable NSString *)expectedKind {
+ return nil;
+}
+
+- (BOOL)setWithDictionary:(NSDictionary *)dictionary
+ error:(NSError *_Nullable *_Nullable)error {
+ _refreshToken = dictionary[kRefreshTokenKey];
+ _accessToken = dictionary[kAccessTokenKey];
+ _IDToken = dictionary[kIDTokenKey];
+ if (!_accessToken.length) {
+ if (error) {
+ *error = [FIRAuthErrorUtils unexpectedResponseWithDeserializedResponse:dictionary];
+ }
+ return NO;
+ }
+ id expiresIn = dictionary[kExpiresInKey];
+ if (![expiresIn isKindOfClass:[NSString class]]) {
+ if (error) {
+ *error = [FIRAuthErrorUtils unexpectedResponseWithDeserializedResponse:dictionary];
+ }
+ return NO;
+ }
+
+ _approximateExpirationDate = [NSDate dateWithTimeIntervalSinceNow:[expiresIn doubleValue]];
+ return YES;
+}
+
+@end
diff --git a/Firebase/Auth/Source/RPCs/FIRSendVerificationCodeRequest.h b/Firebase/Auth/Source/RPCs/FIRSendVerificationCodeRequest.h
new file mode 100644
index 0000000..596fb8c
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRSendVerificationCodeRequest.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRIdentityToolkitRequest.h"
+
+#import "FIRAuthRPCRequest.h"
+#import "FIRIdentityToolkitRequest.h"
+
+@class FIRAuthAppCredential;
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface FIRSendVerificationCodeRequest : FIRIdentityToolkitRequest <FIRAuthRPCRequest>
+
+/** @property phoneNumber
+ @brief The phone number to which the verification code should be sent.
+ */
+@property(nonatomic, strong, readonly) NSString *phoneNumber;
+
+/** @property appCredential
+ @brief The credential to prove the identity of the app in order to send the verification code.
+ */
+@property(nonatomic, strong, readonly) FIRAuthAppCredential *appCredential;
+
+/** @fn initWithEndpoint:APIKey:
+ @brief Please use initWithPhoneNumber:APIKey:
+ */
+- (nullable instancetype)initWithEndpoint:(NSString *)endpoint
+ APIKey:(NSString *)APIKey NS_UNAVAILABLE;
+
+/** @fn initWithPhoneNumber:APIKey:
+ @brief Designated initializer.
+ @param phoneNumber The phone number to which the verification code is to be sent.
+ @param appCredential The credential that proves the identity of the app.
+ @param APIKey The client's API Key.
+ */
+- (nullable instancetype)initWithPhoneNumber:(NSString *)phoneNumber
+ appCredential:(FIRAuthAppCredential *)appCredential
+ APIKey:(NSString *)APIKey NS_DESIGNATED_INITIALIZER;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/RPCs/FIRSendVerificationCodeRequest.m b/Firebase/Auth/Source/RPCs/FIRSendVerificationCodeRequest.m
new file mode 100644
index 0000000..f2212ad
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRSendVerificationCodeRequest.m
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRSendVerificationCodeRequest.h"
+
+#import "../Private/FIRAuthAppCredential.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @var kSendVerificationCodeEndPoint
+ @brief The "sendVerificationCodeEnd" endpoint.
+ */
+static NSString *const kSendVerificationCodeEndPoint = @"sendVerificationCode";
+
+/** @var kPhoneNumberKey
+ @brief The key for the Phone Number parameter in the request.
+ */
+static NSString *const kPhoneNumberKey = @"phoneNumber";
+
+/** @var kReceiptKey
+ @brief The key for the receipt parameter in the request.
+ */
+static NSString *const kReceiptKey = @"iosReceipt";
+
+/** @var kSecretKey
+ @brief The key for the Secret parameter in the request.
+ */
+static NSString *const kSecretKey = @"iosSecret";
+
+@implementation FIRSendVerificationCodeRequest {
+}
+
+- (nullable instancetype)initWithPhoneNumber:(NSString *)phoneNumber
+ appCredential:(FIRAuthAppCredential *)appCredential
+ APIKey:(NSString *)APIKey {
+ self = [super initWithEndpoint:kSendVerificationCodeEndPoint APIKey:APIKey];
+ if (self) {
+ _phoneNumber = [phoneNumber copy];
+ _appCredential = appCredential;
+ }
+ return self;
+}
+
+- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable)error {
+ NSMutableDictionary *postBody = [NSMutableDictionary dictionary];
+ if (_phoneNumber) {
+ postBody[kPhoneNumberKey] = _phoneNumber;
+ }
+ if (_appCredential.receipt) {
+ postBody[kReceiptKey] = _appCredential.receipt;
+ }
+ if (_appCredential.secret) {
+ postBody[kSecretKey] = _appCredential.secret;
+ }
+ return postBody;
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/RPCs/FIRSendVerificationCodeResponse.h b/Firebase/Auth/Source/RPCs/FIRSendVerificationCodeResponse.h
new file mode 100644
index 0000000..1a49ec2
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRSendVerificationCodeResponse.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "FIRAuthRPCResponse.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface FIRSendVerificationCodeResponse : NSObject <FIRAuthRPCResponse>
+
+/** @property verificationID
+ @brief Encrypted session information returned by the backend.
+ */
+@property(nonatomic, readonly) NSString *verificationID;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/RPCs/FIRSendVerificationCodeResponse.m b/Firebase/Auth/Source/RPCs/FIRSendVerificationCodeResponse.m
new file mode 100644
index 0000000..9e47b6e
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRSendVerificationCodeResponse.m
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRSendVerificationCodeResponse.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@implementation FIRSendVerificationCodeResponse
+
+// TODO: remove when resolving b/37169084 .
+- (nullable NSString *)expectedKind {
+ return nil;
+}
+
+- (BOOL)setWithDictionary:(NSDictionary *)dictionary
+ error:(NSError *_Nullable *_Nullable)error {
+ _verificationID = [dictionary[@"sessionInfo"] copy];
+ return YES;
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/RPCs/FIRSetAccountInfoRequest.h b/Firebase/Auth/Source/RPCs/FIRSetAccountInfoRequest.h
new file mode 100644
index 0000000..4816474
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRSetAccountInfoRequest.h
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "FIRAuthRPCRequest.h"
+#import "FIRIdentityToolkitRequest.h"
+
+@class FIRGetAccountInfoResponse;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @var FIRSetAccountInfoUserAttributeEmail
+ @brief Constant for email attribute used in "deleteAttributes".
+ */
+extern NSString *const FIRSetAccountInfoUserAttributeEmail;
+
+/** @var FIRSetAccountInfoUserAttributeDisplayName
+ @brief Constant for displayName attribute used in "deleteAttributes".
+ */
+extern NSString *const FIRSetAccountInfoUserAttributeDisplayName;
+
+/** @var FIRSetAccountInfoUserAttributeProvider
+ @brief Constant for provider attribute used in "deleteAttributes".
+ */
+extern NSString *const FIRSetAccountInfoUserAttributeProvider;
+
+/** @var FIRSetAccountInfoUserAttributePhotoURL
+ @brief Constant for photoURL attribute used in "deleteAttributes".
+ */
+extern NSString *const FIRSetAccountInfoUserAttributePhotoURL;
+
+/** @var FIRSetAccountInfoUserAttributePassword
+ @brief Constant for password attribute used in "deleteAttributes".
+ */
+extern NSString *const FIRSetAccountInfoUserAttributePassword;
+
+/** @class FIRSetAccountInfoRequest
+ @brief Represents the parameters for the setAccountInfo endpoint.
+ @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/setAccountInfo
+ */
+@interface FIRSetAccountInfoRequest : FIRIdentityToolkitRequest <FIRAuthRPCRequest>
+
+/** @property accessToken
+ @brief The STS Access Token of the authenticated user.
+ */
+@property(nonatomic, copy, nullable) NSString *accessToken;
+
+/** @property displayName
+ @brief The name of the user.
+ */
+@property(nonatomic, copy, nullable) NSString *displayName;
+
+/** @property localID
+ @brief The local ID of the user.
+ */
+@property(nonatomic, copy, nullable) NSString *localID;
+
+/** @property email
+ @brief The email of the user.
+ */
+@property(nonatomic, copy, nullable) NSString *email;
+
+/** @property photoURL
+ @brief The photoURL of the user.
+ */
+@property(nonatomic, copy, nullable) NSURL *photoURL;
+
+/** @property password
+ @brief The new password of the user.
+ */
+@property(nonatomic, copy, nullable) NSString *password;
+
+/** @property providers
+ @brief The associated identity providers of the user.
+ */
+@property(nonatomic, copy, nullable) NSArray<NSString *> *providers;
+
+/** @property OOBCode
+ @brief The out-of-band code of the change email request.
+ */
+@property(nonatomic, copy, nullable) NSString *OOBCode;
+
+/** @property emailVerified
+ @brief Whether to mark the email as verified or not.
+ */
+@property(nonatomic, assign) BOOL emailVerified;
+
+/** @property upgradeToFederatedLogin
+ @brief Whether to mark the user to upgrade to federated login.
+ */
+@property(nonatomic, assign) BOOL upgradeToFederatedLogin;
+
+/** @property captchaChallenge
+ @brief The captcha challenge.
+ */
+@property(nonatomic, copy, nullable) NSString *captchaChallenge;
+
+/** @property captchaResponse
+ @brief Response to the captcha.
+ */
+@property(nonatomic, copy, nullable) NSString *captchaResponse;
+
+/** @property deleteAttributes
+ @brief The list of user attributes to delete.
+ @remarks Every element of the list must be one of the predefined constant starts with
+ "FIRSetAccountInfoUserAttribute".
+ */
+@property(nonatomic, copy, nullable) NSArray<NSString *> *deleteAttributes;
+
+/** @property deleteProviders
+ @brief The list of identity providers to delete.
+ */
+@property(nonatomic, copy, nullable) NSArray<NSString *> *deleteProviders;
+
+/** @property returnSecureToken
+ @brief Whether the response should return access token and refresh token directly.
+ @remarks The default value is @c YES .
+ */
+@property(nonatomic, assign) BOOL returnSecureToken;
+
+/** @fn initWithEndpoint:APIKey:
+ @brief Please use initWithAPIKey:
+ */
+- (nullable instancetype)initWithEndpoint:(NSString *)endpoint
+ APIKey:(NSString *)APIKey NS_UNAVAILABLE;
+
+/** @fn initWithAPIKey:
+ @brief Designated initializer.
+ @param APIKey The client's API Key.
+ */
+- (nullable instancetype)initWithAPIKey:(NSString *)APIKey NS_DESIGNATED_INITIALIZER;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/RPCs/FIRSetAccountInfoRequest.m b/Firebase/Auth/Source/RPCs/FIRSetAccountInfoRequest.m
new file mode 100644
index 0000000..b18d0dd
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRSetAccountInfoRequest.m
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRSetAccountInfoRequest.h"
+
+#import "../Private/FIRAuthErrorUtils.h"
+#import "../Private/FIRAuth_Internal.h"
+#import "FIRGetAccountInfoResponse.h"
+
+NSString *const FIRSetAccountInfoUserAttributeEmail = @"EMAIL";
+
+NSString *const FIRSetAccountInfoUserAttributeDisplayName = @"DISPLAY_NAME";
+
+NSString *const FIRSetAccountInfoUserAttributeProvider = @"PROVIDER";
+
+NSString *const FIRSetAccountInfoUserAttributePhotoURL = @"PHOTO_URL";
+
+NSString *const FIRSetAccountInfoUserAttributePassword = @"PASSWORD";
+
+/** @var kCreateAuthURIEndpoint
+ @brief The "setAccountInfo" endpoint.
+ */
+static NSString *const kSetAccountInfoEndpoint = @"setAccountInfo";
+
+/** @var kIDTokenKey
+ @brief The key for the "idToken" value in the request. This is actually the STS Access Token,
+ despite it's confusing (backwards compatiable) parameter name.
+ */
+static NSString *const kIDTokenKey = @"idToken";
+
+/** @var kDisplayNameKey
+ @brief The key for the "displayName" value in the request.
+ */
+static NSString *const kDisplayNameKey = @"displayName";
+
+/** @var kLocalIDKey
+ @brief The key for the "localID" value in the request.
+ */
+static NSString *const kLocalIDKey = @"localId";
+
+/** @var kEmailKey
+ @brief The key for the "email" value in the request.
+ */
+static NSString *const kEmailKey = @"email";
+
+/** @var kPasswordKey
+ @brief The key for the "password" value in the request.
+ */
+static NSString *const kPasswordKey = @"password";
+
+/** @var kPhotoURLKey
+ @brief The key for the "photoURL" value in the request.
+ */
+static NSString *const kPhotoURLKey = @"photoUrl";
+
+/** @var kProvidersKey
+ @brief The key for the "providers" value in the request.
+ */
+static NSString *const kProvidersKey = @"provider";
+
+/** @var kOOBCodeKey
+ @brief The key for the "OOBCode" value in the request.
+ */
+static NSString *const kOOBCodeKey = @"oobCode";
+
+/** @var kEmailVerifiedKey
+ @brief The key for the "emailVerified" value in the request.
+ */
+static NSString *const kEmailVerifiedKey = @"emailVerified";
+
+/** @var kUpgradeToFederatedLoginKey
+ @brief The key for the "upgradeToFederatedLogin" value in the request.
+ */
+static NSString *const kUpgradeToFederatedLoginKey = @"upgradeToFederatedLogin";
+
+/** @var kCaptchaChallengeKey
+ @brief The key for the "captchaChallenge" value in the request.
+ */
+static NSString *const kCaptchaChallengeKey = @"captchaChallenge";
+
+/** @var kCaptchaResponseKey
+ @brief The key for the "captchaResponse" value in the request.
+ */
+static NSString *const kCaptchaResponseKey = @"captchaResponse";
+
+/** @var kDeleteAttributesKey
+ @brief The key for the "deleteAttribute" value in the request.
+ */
+static NSString *const kDeleteAttributesKey = @"deleteAttribute";
+
+/** @var kDeleteProvidersKey
+ @brief The key for the "deleteProvider" value in the request.
+ */
+static NSString *const kDeleteProvidersKey = @"deleteProvider";
+
+/** @var kReturnSecureTokenKey
+ @brief The key for the "returnSecureToken" value in the request.
+ */
+static NSString *const kReturnSecureTokenKey = @"returnSecureToken";
+
+@implementation FIRSetAccountInfoRequest
+
+- (nullable instancetype)initWithAPIKey:(NSString *)APIKey {
+ self = [super initWithEndpoint:kSetAccountInfoEndpoint APIKey:APIKey];
+ if (self) {
+ _returnSecureToken = YES;
+ }
+ return self;
+}
+
+- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable)error {
+ NSMutableDictionary *postBody = [NSMutableDictionary dictionary];
+ if (_accessToken) {
+ postBody[kIDTokenKey] = _accessToken;
+ }
+ if (_displayName) {
+ postBody[kDisplayNameKey] = _displayName;
+ }
+ if (_localID) {
+ postBody[kLocalIDKey] = _localID;
+ }
+ if (_email) {
+ postBody[kEmailKey] = _email;
+ }
+ if (_password) {
+ postBody[kPasswordKey] = _password;
+ }
+ if (_photoURL) {
+ postBody[kPhotoURLKey] = _photoURL.absoluteString;
+ }
+ if (_providers) {
+ postBody[kProvidersKey] = _providers;
+ }
+ if (_OOBCode) {
+ postBody[kOOBCodeKey] = _OOBCode;
+ }
+ if (_emailVerified) {
+ postBody[kEmailVerifiedKey] = @YES;
+ }
+ if (_upgradeToFederatedLogin) {
+ postBody[kUpgradeToFederatedLoginKey] = @YES;
+ }
+ if (_captchaChallenge) {
+ postBody[kCaptchaChallengeKey] = _captchaChallenge;
+ }
+ if (_captchaResponse) {
+ postBody[kCaptchaResponseKey] = _captchaResponse;
+ }
+ if (_deleteAttributes) {
+ postBody[kDeleteAttributesKey] = _deleteAttributes;
+ }
+ if (_deleteProviders) {
+ postBody[kDeleteProvidersKey] = _deleteProviders;
+ }
+ if (_returnSecureToken) {
+ postBody[kReturnSecureTokenKey] = @YES;
+ }
+ return postBody;
+}
+
+@end
diff --git a/Firebase/Auth/Source/RPCs/FIRSetAccountInfoResponse.h b/Firebase/Auth/Source/RPCs/FIRSetAccountInfoResponse.h
new file mode 100644
index 0000000..92895c0
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRSetAccountInfoResponse.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "FIRAuthRPCResponse.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @class FIRSetAccountInfoResponseProviderUserInfo
+ @brief Represents the provider user info part of the response from the setAccountInfo endpoint.
+ @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/setAccountInfo
+ */
+@interface FIRSetAccountInfoResponseProviderUserInfo : NSObject
+
+/** @property providerID
+ @brief The ID of the identity provider.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *providerID;
+
+/** @property displayName
+ @brief The user's display name at the identity provider.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *displayName;
+
+/** @property photoURL
+ @brief The user's photo URL at the identity provider.
+ */
+@property(nonatomic, strong, readonly, nullable) NSURL *photoURL;
+
+/** @fn init
+ @brief Please use initWithDictionary:
+ */
+- (instancetype)init NS_UNAVAILABLE;
+
+/** @fn initWithAPIKey:
+ @brief Designated initializer.
+ @param dictionary The provider user info data from endpoint.
+ */
+- (instancetype)initWithDictionary:(NSDictionary *)dictionary NS_DESIGNATED_INITIALIZER;
+
+@end
+
+/** @class FIRSetAccountInfoResponse
+ @brief Represents the response from the setAccountInfo endpoint.
+ @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/setAccountInfo
+ */
+@interface FIRSetAccountInfoResponse : NSObject <FIRAuthRPCResponse>
+
+/** @property email
+ @brief The email or the user.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *email;
+
+/** @property displayName
+ @brief The display name of the user.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *displayName;
+
+/** @property providerUserInfo
+ @brief The user's profiles at the associated identity providers.
+ */
+@property(nonatomic, strong, readonly, nullable)
+ NSArray<FIRSetAccountInfoResponseProviderUserInfo *> *providerUserInfo;
+
+/** @property IDToken
+ @brief Either an authorization code suitable for performing an STS token exchange, or the
+ access token from Secure Token Service, depending on whether @c returnSecureToken is set
+ on the request.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *IDToken;
+
+/** @property approximateExpirationDate
+ @brief The approximate expiration date of the access token.
+ */
+@property(nonatomic, copy, readonly, nullable) NSDate *approximateExpirationDate;
+
+/** @property refreshToken
+ @brief The refresh token from Secure Token Service.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *refreshToken;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/RPCs/FIRSetAccountInfoResponse.m b/Firebase/Auth/Source/RPCs/FIRSetAccountInfoResponse.m
new file mode 100644
index 0000000..140ba25
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRSetAccountInfoResponse.m
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRSetAccountInfoResponse.h"
+
+#import "../Private/FIRAuthErrorUtils.h"
+
+@implementation FIRSetAccountInfoResponseProviderUserInfo
+
+- (instancetype)initWithDictionary:(NSDictionary *)dictionary {
+ self = [super init];
+ if (self) {
+ _providerID = [dictionary[@"providerId"] copy];
+ _displayName = [dictionary[@"displayName"] copy];
+ NSString *photoURL = dictionary[@"photoUrl"];
+ if (photoURL) {
+ _photoURL = [NSURL URLWithString:photoURL];
+ }
+ }
+ return self;
+}
+
+@end
+
+@implementation FIRSetAccountInfoResponse
+
+- (BOOL)setWithDictionary:(NSDictionary *)dictionary
+ error:(NSError *_Nullable *_Nullable)error {
+ _email = [dictionary[@"email"] copy];
+ _displayName = [dictionary[@"displayName"] copy];
+ _IDToken = [dictionary[@"idToken"] copy];
+ _approximateExpirationDate = [dictionary[@"expiresIn"] isKindOfClass:[NSString class]] ?
+ [NSDate dateWithTimeIntervalSinceNow:[dictionary[@"expiresIn"] doubleValue]] : nil;
+ _refreshToken = [dictionary[@"refreshToken"] copy];
+ NSArray<NSDictionary *> *providerUserInfoData = dictionary[@"providerUserInfo"];
+ if (providerUserInfoData) {
+ NSMutableArray<FIRSetAccountInfoResponseProviderUserInfo *> *providerUserInfoArray =
+ [NSMutableArray arrayWithCapacity:providerUserInfoData.count];
+ for (NSDictionary *dictionary in providerUserInfoData) {
+ [providerUserInfoArray addObject:
+ [[FIRSetAccountInfoResponseProviderUserInfo alloc] initWithDictionary:dictionary]];
+ }
+ _providerUserInfo = [providerUserInfoArray copy];
+ }
+ return YES;
+}
+
+@end
diff --git a/Firebase/Auth/Source/RPCs/FIRSignUpNewUserRequest.h b/Firebase/Auth/Source/RPCs/FIRSignUpNewUserRequest.h
new file mode 100644
index 0000000..46b47d5
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRSignUpNewUserRequest.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "FIRAuthRPCRequest.h"
+#import "FIRIdentityToolkitRequest.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface FIRSignUpNewUserRequest : FIRIdentityToolkitRequest <FIRAuthRPCRequest>
+
+/** @property email
+ @brief The email of the user.
+ */
+@property(nonatomic, copy, nullable) NSString *email;
+
+/** @property password
+ @brief The password inputed by the user.
+ */
+@property(nonatomic, copy, nullable) NSString *password;
+
+/** @property displayName
+ @brief The password inputed by the user.
+ */
+@property(nonatomic, copy, nullable) NSString *displayName;
+
+/** @property returnSecureToken
+ @brief Whether the response should return access token and refresh token directly.
+ @remarks The default value is @c YES .
+ */
+@property(nonatomic, assign) BOOL returnSecureToken;
+
+/** @fn initWithEndpoint:APIKey:
+ @brief Please use initWithEmail:password:APIKey:
+ */
+- (nullable instancetype)initWithEndpoint:(NSString *)endpoint
+ APIKey:(NSString *)APIKey NS_UNAVAILABLE;
+/** @fn initWithAPIKey:
+ @brief initializer for anonymous sign-in.
+ */
+- (nullable instancetype)initWithAPIKey:(NSString *)APIKey;
+
+/** @fn initWithAPIKey:email:password:
+ @brief Designated initializer.
+ */
+- (nullable instancetype)initWithAPIKey:(NSString *)APIKey
+ email:(nullable NSString *)email
+ password:(nullable NSString *)password
+ displayName:(nullable NSString *)displayName NS_DESIGNATED_INITIALIZER;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/RPCs/FIRSignUpNewUserRequest.m b/Firebase/Auth/Source/RPCs/FIRSignUpNewUserRequest.m
new file mode 100644
index 0000000..af60b11
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRSignUpNewUserRequest.m
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRSignUpNewUserRequest.h"
+
+/** @var kSignupNewUserEndpoint
+ @brief The "SingupNewUserEndpoint" endpoint.
+ */
+static NSString *const kSignupNewUserEndpoint = @"signupNewUser";
+
+/** @var kEmailKey
+ @brief The key for the "email" value in the request.
+ */
+static NSString *const kEmailKey = @"email";
+
+/** @var kPasswordKey
+ @brief The key for the "password" value in the request.
+ */
+static NSString *const kPasswordKey = @"password";
+
+/** @var kDisplayNameKey
+ @brief The key for the "kDisplayName" value in the request.
+ */
+static NSString *const kDisplayNameKey = @"displayName";
+
+/** @var kReturnSecureTokenKey
+ @brief The key for the "returnSecureToken" value in the request.
+ */
+static NSString *const kReturnSecureTokenKey = @"returnSecureToken";
+
+@implementation FIRSignUpNewUserRequest
+
+- (nullable instancetype)initWithAPIKey:(NSString *)APIKey
+ email:(NSString *)email
+ password:(NSString *)password
+ displayName:(NSString *)displayName {
+ self = [super initWithEndpoint:kSignupNewUserEndpoint APIKey:APIKey];
+ if (self) {
+ _email = [email copy];
+ _password = [password copy];
+ _displayName = [displayName copy];
+ _returnSecureToken = YES;
+ }
+ return self;
+}
+
+- (nullable instancetype)initWithAPIKey:(NSString *)APIKey{
+ self = [self initWithAPIKey:APIKey email:nil password:nil displayName:nil];
+ return self;
+}
+
+- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable)error {
+ NSMutableDictionary *postBody = [NSMutableDictionary dictionary];
+ if (_email) {
+ postBody[kEmailKey] = _email;
+ }
+ if (_password) {
+ postBody[kPasswordKey] = _password;
+ }
+ if (_displayName) {
+ postBody[kDisplayNameKey] = _displayName;
+ }
+ if (_returnSecureToken) {
+ postBody[kReturnSecureTokenKey] = @YES;
+ }
+ return postBody;
+}
+
+@end
diff --git a/Firebase/Auth/Source/RPCs/FIRSignUpNewUserResponse.h b/Firebase/Auth/Source/RPCs/FIRSignUpNewUserResponse.h
new file mode 100644
index 0000000..0d55939
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRSignUpNewUserResponse.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "FIRAuthRPCResponse.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface FIRSignUpNewUserResponse : NSObject<FIRAuthRPCResponse>
+
+/** @property IDToken
+ @brief Either an authorization code suitable for performing an STS token exchange, or the
+ access token from Secure Token Service, depending on whether @c returnSecureToken is set
+ on the request.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *IDToken;
+
+/** @property approximateExpirationDate
+ @brief The approximate expiration date of the access token.
+ */
+@property(nonatomic, copy, readonly, nullable) NSDate *approximateExpirationDate;
+
+/** @property refreshToken
+ @brief The refresh token from Secure Token Service.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *refreshToken;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/RPCs/FIRSignUpNewUserResponse.m b/Firebase/Auth/Source/RPCs/FIRSignUpNewUserResponse.m
new file mode 100644
index 0000000..4196d21
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRSignUpNewUserResponse.m
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRSignUpNewUserResponse.h"
+
+#import "../Private/FIRAuthErrorUtils.h"
+
+@implementation FIRSignUpNewUserResponse
+
+- (BOOL)setWithDictionary:(NSDictionary *)dictionary
+ error:(NSError *_Nullable *_Nullable)error {
+ _IDToken = [dictionary[@"idToken"] copy];
+ _approximateExpirationDate = [dictionary[@"expiresIn"] isKindOfClass:[NSString class]] ?
+ [NSDate dateWithTimeIntervalSinceNow:[dictionary[@"expiresIn"] doubleValue]] : nil;
+ _refreshToken = [dictionary[@"refreshToken"] copy];
+ return YES;
+}
+
+@end
diff --git a/Firebase/Auth/Source/RPCs/FIRVerifyAssertionRequest.h b/Firebase/Auth/Source/RPCs/FIRVerifyAssertionRequest.h
new file mode 100644
index 0000000..3202b47
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRVerifyAssertionRequest.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "FIRAuthRPCRequest.h"
+#import "FIRIdentityToolkitRequest.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @class FIRVerifyAssertionRequest
+ @brief Represents the parameters for the verifyAssertion endpoint.
+ @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/verifyAssertion
+ */
+@interface FIRVerifyAssertionRequest : FIRIdentityToolkitRequest <FIRAuthRPCRequest>
+
+/** @property requestURI
+ @brief The URI to which the IDP redirects the user back. It may contain federated login result
+ params added by the IDP.
+ */
+@property(nonatomic, copy, nullable) NSString *requestURI;
+
+/** @property pendingIDToken
+ @brief The Firebase ID Token for the non-trusted IDP pending to be confirmed by the user.
+ */
+@property(nonatomic, copy, nullable) NSString *pendingIDToken;
+
+/** @property accessToken
+ @brief The STS Access Token for the authenticated user, only needed for linking the user.
+ */
+@property(nonatomic, copy, nullable) NSString *accessToken;
+
+/** @property returnSecureToken
+ @brief Whether the response should return access token and refresh token directly.
+ @remarks The default value is @c YES .
+ */
+@property(nonatomic, assign) BOOL returnSecureToken;
+
+#pragma mark - Components of "postBody"
+
+/** @property providerID
+ @brief The ID of the IDP whose credentials are being presented to the endpoint.
+ */
+@property(nonatomic, copy, readonly) NSString *providerID;
+
+/** @property providerAccessToken
+ @brief An access token from the IDP.
+ */
+@property(nonatomic, copy, nullable) NSString *providerAccessToken;
+
+/** @property providerIDToken
+ @brief An ID Token from the IDP.
+ */
+@property(nonatomic, copy, nullable) NSString *providerIDToken;
+
+/** @property providerOAuthTokenSecret
+ @brief An OAuth client secret from the IDP.
+ */
+@property(nonatomic, copy, nullable) NSString *providerOAuthTokenSecret;
+
+/** @property inputEmail
+ @brief The originally entered email in the UI.
+ */
+@property(nonatomic, copy, nullable) NSString *inputEmail;
+
+/** @property autoCreate
+ @brief A flag that indicates whether or not the user should be automatically created.
+ */
+@property(nonatomic, assign) BOOL autoCreate;
+
+/** @fn initWithEndpoint:APIKey:
+ @brief Please use initWithAPIKey:
+ */
+- (nullable instancetype)initWithEndpoint:(NSString *)endpoint
+ APIKey:(NSString *)APIKey NS_UNAVAILABLE;
+
+/** @fn initWithAPIKey:
+ @brief Designated initializer.
+ @param APIKey The client's API Key.
+ @param providerID The auth provider's ID.
+ */
+- (nullable instancetype)initWithAPIKey:(NSString *)APIKey
+ providerID:(NSString *)providerID NS_DESIGNATED_INITIALIZER;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/RPCs/FIRVerifyAssertionRequest.m b/Firebase/Auth/Source/RPCs/FIRVerifyAssertionRequest.m
new file mode 100644
index 0000000..b31ae42
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRVerifyAssertionRequest.m
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRVerifyAssertionRequest.h"
+
+#import <GoogleToolboxForMac/GTMNSData+zlib.h>
+#import <GoogleToolboxForMac/GTMNSDictionary+URLArguments.h>
+
+/** @var kVerifyAssertionEndpoint
+ @brief The "verifyAssertion" endpoint.
+ */
+static NSString *const kVerifyAssertionEndpoint = @"verifyAssertion";
+
+/** @var kProviderIDKey
+ @brief The key for the "providerId" value in the request.
+ */
+static NSString *const kProviderIDKey = @"providerId";
+
+/** @var kProviderIDTokenKey
+ @brief The key for the "id_token" value in the request.
+ */
+static NSString *const kProviderIDTokenKey = @"id_token";
+
+/** @var kProviderAccessTokenKey
+ @brief The key for the "access_token" value in the request.
+ */
+static NSString *const kProviderAccessTokenKey = @"access_token";
+
+/** @var kProviderOAuthTokenSecretKey
+ @brief The key for the "oauth_token_secret" value in the request.
+ */
+static NSString *const kProviderOAuthTokenSecretKey = @"oauth_token_secret";
+
+/** @var kIdentifierKey
+ @brief The key for the "identifier" value in the request.
+ */
+static NSString *const kIdentifierKey = @"identifier";
+
+/** @var kRequestURIKey
+ @brief The key for the "requestUri" value in the request.
+ */
+static NSString *const kRequestURIKey = @"requestUri";
+
+/** @var kPostBodyKey
+ @brief The key for the "postBody" value in the request.
+ */
+static NSString *const kPostBodyKey = @"postBody";
+
+/** @var kPendingIDTokenKey
+ @brief The key for the "pendingIdToken" value in the request.
+ */
+static NSString *const kPendingIDTokenKey = @"pendingIdToken";
+
+/** @var kAutoCreateKey
+ @brief The key for the "autoCreate" value in the request.
+ */
+static NSString *const kAutoCreateKey = @"autoCreate";
+
+/** @var kIDTokenKey
+ @brief The key for the "idToken" value in the request. This is actually the STS Access Token,
+ despite it's confusing (backwards compatiable) parameter name.
+ */
+static NSString *const kIDTokenKey = @"idToken";
+
+/** @var kReturnSecureTokenKey
+ @brief The key for the "returnSecureToken" value in the request.
+ */
+static NSString *const kReturnSecureTokenKey = @"returnSecureToken";
+
+@implementation FIRVerifyAssertionRequest
+
+- (nullable instancetype)initWithAPIKey:(NSString *)APIKey
+ providerID:(nonnull NSString *)providerID{
+ self = [super initWithEndpoint:kVerifyAssertionEndpoint APIKey:APIKey];
+ if (self) {
+ _providerID = providerID;
+ _returnSecureToken = YES;
+ _autoCreate = YES;
+ }
+ return self;
+}
+
+- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable)error {
+ NSMutableDictionary *postBody = [@{
+ kProviderIDKey : _providerID,
+ } mutableCopy];
+
+ if (_providerIDToken) {
+ postBody[kProviderIDTokenKey] = _providerIDToken;
+ }
+
+ if (_providerAccessToken) {
+ postBody[kProviderAccessTokenKey] = _providerAccessToken;
+ }
+
+ if (!_providerIDToken && !_providerAccessToken) {
+ [NSException raise:NSInvalidArgumentException
+ format:@"Either IDToken or accessToken must be supplied."];
+ }
+
+ if (_providerOAuthTokenSecret) {
+ postBody[kProviderOAuthTokenSecretKey] = _providerOAuthTokenSecret;
+ }
+
+ if (_inputEmail) {
+ postBody[kIdentifierKey] = _inputEmail;
+ }
+
+ NSMutableDictionary *body = [@{
+ kRequestURIKey : @"http://localhost", // Unused by server, but required
+ kPostBodyKey : [postBody gtm_httpArgumentsString]
+ } mutableCopy];
+
+ if (_pendingIDToken) {
+ body[kPendingIDTokenKey] = _pendingIDToken;
+ }
+ if (_accessToken) {
+ body[kIDTokenKey] = _accessToken;
+ }
+ if (_returnSecureToken) {
+ body[kReturnSecureTokenKey] = @YES;
+ }
+
+ body[kAutoCreateKey] = @(_autoCreate);
+
+ return body;
+}
+
+@end
diff --git a/Firebase/Auth/Source/RPCs/FIRVerifyAssertionResponse.h b/Firebase/Auth/Source/RPCs/FIRVerifyAssertionResponse.h
new file mode 100644
index 0000000..ce796ee
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRVerifyAssertionResponse.h
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "FIRAuthRPCResponse.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @class FIRVerifyAssertionResponse
+ @brief Represents the response from the verifyAssertion endpoint.
+ @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/verifyAssertion
+ */
+@interface FIRVerifyAssertionResponse : NSObject <FIRAuthRPCResponse>
+
+/** @property federatedID
+ @brief The unique ID identifies the IdP account.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *federatedID;
+
+/** @property providerID
+ @brief The IdP ID. For white listed IdPs it's a short domain name e.g. google.com, aol.com,
+ live.net and yahoo.com. If the "providerId" param is set to OpenID OP identifer other than
+ the whilte listed IdPs the OP identifier is returned. If the "identifier" param is federated
+ ID in the createAuthUri request. The domain part of the federated ID is returned.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *providerID;
+
+/** @property localID
+ @brief The RP local ID if it's already been mapped to the IdP account identified by the
+ federated ID.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *localID;
+
+/** @property email
+ @brief The email returned by the IdP. NOTE: The federated login user may not own the email.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *email;
+
+/** @property inputEmail
+ @brief It's the identifier param in the createAuthUri request if the identifier is an email. It
+ can be used to check whether the user input email is different from the asserted email.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *inputEmail;
+
+/** @property originalEmail
+ @brief The original email stored in the mapping storage. It's returned when the federated ID is
+ associated to a different email.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *originalEmail;
+
+/** @property oauthRequestToken
+ @brief The user approved request token for the OpenID OAuth extension.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *oauthRequestToken;
+
+/** @property oauthScope
+ @brief The scope for the OpenID OAuth extension.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *oauthScope;
+
+/** @property firstName
+ @brief The first name of the user.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *firstName;
+
+/** @property lastName
+ @brief The last name of the user.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *lastName;
+
+/** @property fullName
+ @brief The full name of the user.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *fullName;
+
+/** @property nickName
+ @brief The nick name of the user.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *nickName;
+
+/** @property displayName
+ @brief The display name of the user.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *displayName;
+
+/** @property IDToken
+ @brief Either an authorization code suitable for performing an STS token exchange, or the
+ access token from Secure Token Service, depending on whether @c returnSecureToken is set
+ on the request.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *IDToken;
+
+/** @property approximateExpirationDate
+ @brief The approximate expiration date of the access token.
+ */
+@property(nonatomic, copy, readonly, nullable) NSDate *approximateExpirationDate;
+
+/** @property refreshToken
+ @brief The refresh token from Secure Token Service.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *refreshToken;
+
+/** @property action
+ @brief The action code.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *action;
+
+/** @property language
+ @brief The language preference of the user.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *language;
+
+/** @property timeZone
+ @brief The timezone of the user.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *timeZone;
+
+/** @property photoURL
+ @brief The URI of the public accessible profile picture.
+ */
+@property(nonatomic, strong, readonly, nullable) NSURL *photoURL;
+
+/** @property dateOfBirth
+ @brief The birth date of the IdP account.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *dateOfBirth;
+
+/** @property context
+ @brief The opaque value used by the client to maintain context info between the authentication
+ request and the IDP callback.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *context;
+
+/** @property verifiedProvider
+ @brief When action is 'map', contains the idps which can be used for confirmation.
+ */
+@property(nonatomic, strong, readonly, nullable) NSArray<NSString *> *verifiedProvider;
+
+/** @property needConfirmation
+ @brief Whether the assertion is from a non-trusted IDP and need account linking confirmation.
+ */
+@property(nonatomic, assign) BOOL needConfirmation;
+
+/** @property emailRecycled
+ @brief It's true if the email is recycled.
+ */
+@property(nonatomic, assign) BOOL emailRecycled;
+
+/** @property emailVerified
+ @brief The value is true if the IDP is also the email provider. It means the user owns the
+ email.
+ */
+@property(nonatomic, assign) BOOL emailVerified;
+
+/** @property isNewUser
+ @brief Flag indicating that the user signing in is a new user and not a returning user.
+ */
+@property(nonatomic, assign) BOOL isNewUser;
+
+/** @property profile
+ @brief Dictionary containing the additional IdP specific information.
+ */
+@property(nonatomic, readonly, nullable) NSDictionary<NSString *, NSObject *> *profile;
+
+/** @property username
+ @brief The name of the user.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *username;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/RPCs/FIRVerifyAssertionResponse.m b/Firebase/Auth/Source/RPCs/FIRVerifyAssertionResponse.m
new file mode 100644
index 0000000..6ae33c6
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRVerifyAssertionResponse.m
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRVerifyAssertionResponse.h"
+
+#import "../Private/FIRAuthErrorUtils.h"
+
+@implementation FIRVerifyAssertionResponse
+
+- (BOOL)setWithDictionary:(NSDictionary *)dictionary
+ error:(NSError *_Nullable *_Nullable)error {
+ _federatedID = [dictionary[@"federatedId"] copy];
+ _providerID = [dictionary[@"providerId"] copy];
+ _localID = [dictionary[@"localId"] copy];
+ _emailRecycled = [dictionary[@"emailRecycled"] boolValue];
+ _emailVerified = [dictionary[@"emailVerified"] boolValue];
+ _email = [dictionary[@"email"] copy];
+ _inputEmail = [dictionary[@"inputEmail"] copy];
+ _originalEmail = [dictionary[@"originalEmail"] copy];
+ _oauthRequestToken = [dictionary[@"oauthRequestToken"] copy];
+ _oauthScope = [dictionary[@"oauthScope"] copy];
+ _firstName = [dictionary[@"firstName"] copy];
+ _lastName = [dictionary[@"lastName"] copy];
+ _fullName = [dictionary[@"fullName"] copy];
+ _nickName = [dictionary[@"nickName"] copy];
+ _displayName = [dictionary[@"displayName"] copy];
+ _IDToken = [dictionary[@"idToken"] copy];
+ _approximateExpirationDate = [dictionary[@"expiresIn"] isKindOfClass:[NSString class]] ?
+ [NSDate dateWithTimeIntervalSinceNow:[dictionary[@"expiresIn"] doubleValue]] : nil;
+ _refreshToken = [dictionary[@"refreshToken"] copy];
+ _isNewUser = [dictionary[@"isNewUser"] boolValue];
+ id rawUserInfo = dictionary[@"rawUserInfo"];
+ if ([rawUserInfo isKindOfClass:[NSString class]]) {
+ NSData *data = [rawUserInfo dataUsingEncoding:NSUTF8StringEncoding];
+ rawUserInfo = [NSJSONSerialization JSONObjectWithData:data
+ options:NSJSONReadingMutableLeaves
+ error:nil];
+ }
+ if ([rawUserInfo isKindOfClass:[NSDictionary class]]) {
+ _profile = [[NSDictionary alloc] initWithDictionary:rawUserInfo
+ copyItems:YES];
+ }
+ _username = [dictionary[@"username"] copy];
+ _action = [dictionary[@"action"] copy];
+ _language = [dictionary[@"language"] copy];
+ _timeZone = [dictionary[@"timeZone"] copy];
+ _photoURL = dictionary[@"photoUrl"] ? [NSURL URLWithString:dictionary[@"photoUrl"]] : nil;
+ _dateOfBirth = [dictionary[@"dateOfBirth"] copy];
+ _context = [dictionary[@"context"] copy];
+ _needConfirmation = [dictionary[@"needConfirmation"] boolValue];
+ id verifiedProvider = dictionary[@"verifiedProvider"];
+ if ([verifiedProvider isKindOfClass:[NSString class]]) {
+ NSData *data = [verifiedProvider dataUsingEncoding:NSUTF8StringEncoding];
+ verifiedProvider = [NSJSONSerialization JSONObjectWithData:data
+ options:NSJSONReadingMutableLeaves
+ error:nil];
+ }
+ if ([verifiedProvider isKindOfClass:[NSArray class]]) {
+ _verifiedProvider = [[NSArray alloc] initWithArray:verifiedProvider
+ copyItems:YES];
+ }
+ return YES;
+}
+
+@end
diff --git a/Firebase/Auth/Source/RPCs/FIRVerifyClientRequest.h b/Firebase/Auth/Source/RPCs/FIRVerifyClientRequest.h
new file mode 100644
index 0000000..b5da6b8
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRVerifyClientRequest.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRIdentityToolkitRequest.h"
+
+#import "FIRAuthRPCRequest.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface FIRVerifyClientRequest : FIRIdentityToolkitRequest <FIRAuthRPCRequest>
+
+/** @property appToken
+ @brief The APNS device token.
+ */
+@property(nonatomic, readonly, nullable) NSString *appToken;
+
+/** @property isSandbox
+ @brief The flag that denotes if the appToken pertains to Sandbox or Production.
+ */
+@property(nonatomic, assign, readonly) BOOL isSandbox;
+
+/** @fn initWithEndpoint:APIKey:
+ @brief Please use initWithAppToken:isSandbox: instead.
+ */
+- (nullable instancetype)initWithEndpoint:(NSString *)endpoint
+ APIKey:(NSString *)APIKey NS_UNAVAILABLE;
+
+/** @fn initWithAppToken:isSandbox:
+ @brief Designated initializer.
+ @param appToken The APNS device token.
+ @param isSandbox The flag indicating whether or not the app token provided is for Sandbox or
+ Production.
+ */
+- (nullable instancetype)initWithAppToken:(NSString *)appToken
+ isSandbox:(BOOL)isSandbox
+ APIKey:(NSString *)APIKey NS_DESIGNATED_INITIALIZER;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/RPCs/FIRVerifyClientRequest.m b/Firebase/Auth/Source/RPCs/FIRVerifyClientRequest.m
new file mode 100644
index 0000000..7b4b469
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRVerifyClientRequest.m
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRVerifyClientRequest.h"
+
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @var kVerifyClientEndpoint
+ @brief The endpoint for the verifyClient request.
+ */
+static NSString *const kVerifyClientEndpoint = @"verifyClient";
+
+/** @var kAppTokenKey
+ @brief The key for the appToken request paramenter.
+ */
+static NSString *const kAPPTokenKey = @"appToken";
+
+/** @var kIsSandboxKey
+ @brief The key for the isSandbox request parameter
+ */
+static NSString *const kIsSandboxKey = @"isSandbox";
+
+@implementation FIRVerifyClientRequest
+
+- (nullable instancetype)initWithAppToken:(NSString *)appToken
+ isSandbox:(BOOL)isSandbox
+ APIKey:(NSString *)APIKey {
+ self = [super initWithEndpoint:kVerifyClientEndpoint APIKey:APIKey];
+ if (self) {
+ _appToken = appToken;
+ _isSandbox = isSandbox;
+ }
+ return self;
+}
+
+- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *__autoreleasing _Nullable *)error {
+ NSMutableDictionary *postBody = [NSMutableDictionary dictionary];
+ if (_appToken) {
+ postBody[kAPPTokenKey] = _appToken;
+ }
+ if (_isSandbox) {
+ postBody[kIsSandboxKey] = @YES;
+ }
+ return postBody;
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/RPCs/FIRVerifyClientResponse.h b/Firebase/Auth/Source/RPCs/FIRVerifyClientResponse.h
new file mode 100644
index 0000000..794256a
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRVerifyClientResponse.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "FIRAuthRPCResponse.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface FIRVerifyClientResponse : NSObject <FIRAuthRPCResponse>
+
+/** @property receipt
+ @brief Receipt that the APNS token was successfully validated with APNS.
+ */
+@property(nonatomic, copy, readonly, nullable) NSString *receipt;
+
+/** @property suggestedTimeOut
+ @brief The date after which delivery of the silent push notification is considered to have
+ failed.
+ */
+@property(nonatomic, copy, readonly, nullable) NSDate *suggestedTimeOutDate;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/RPCs/FIRVerifyClientResponse.m b/Firebase/Auth/Source/RPCs/FIRVerifyClientResponse.m
new file mode 100644
index 0000000..c2477d2
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRVerifyClientResponse.m
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRVerifyClientResponse.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@implementation FIRVerifyClientResponse
+
+- (BOOL)setWithDictionary:(NSDictionary *)dictionary
+ error:(NSError *_Nullable *_Nullable)error {
+ _receipt = dictionary[@"receipt"];
+ _suggestedTimeOutDate = [dictionary[@"suggestedTimeout"] isKindOfClass:[NSString class]] ?
+ [NSDate dateWithTimeIntervalSinceNow:[dictionary[@"suggestedTimeout"] doubleValue]] : nil;
+ return YES;
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/RPCs/FIRVerifyCustomTokenRequest.h b/Firebase/Auth/Source/RPCs/FIRVerifyCustomTokenRequest.h
new file mode 100644
index 0000000..20f3f4d
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRVerifyCustomTokenRequest.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "FIRAuthRPCRequest.h"
+#import "FIRIdentityToolkitRequest.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @class FIRVerifyCustomTokenRequest
+ @brief Represents the parameters for the verifyCustomToken endpoint.
+ */
+@interface FIRVerifyCustomTokenRequest : FIRIdentityToolkitRequest <FIRAuthRPCRequest>
+
+/** @property token
+ @brief The self-signed token from the client's BYOAuth server.
+ */
+@property(nonatomic, copy, readonly) NSString *token;
+
+/** @property returnSecureToken
+ @brief Whether the response should return access token and refresh token directly.
+ @remarks The default value is @c YES .
+ */
+@property(nonatomic, assign) BOOL returnSecureToken;
+
+/** @fn initWithEndpoint:APIKey:
+ @brief Please use initWithToken:APIKey:
+ */
+- (nullable instancetype)initWithEndpoint:(NSString *)endpoint
+ APIKey:(NSString *)APIKey NS_UNAVAILABLE;
+
+/** @fn initWithToken:APIKey:
+ @brief Designated initializer.
+ @param token The self-signed token from the client's BYOAuth server.
+ @param APIKey The client's API Key.
+ */
+- (nullable instancetype)initWithToken:(NSString *)token
+ APIKey:(NSString *)APIKey NS_DESIGNATED_INITIALIZER;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/RPCs/FIRVerifyCustomTokenRequest.m b/Firebase/Auth/Source/RPCs/FIRVerifyCustomTokenRequest.m
new file mode 100644
index 0000000..63d72d1
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRVerifyCustomTokenRequest.m
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRVerifyCustomTokenRequest.h"
+
+/** @var kVerifyCustomTokenEndpoint
+ @brief The "verifyPassword" endpoint.
+ */
+static NSString *const kVerifyCustomTokenEndpoint = @"verifyCustomToken";
+
+/** @var kTokenKey
+ @brief The key for the "token" value in the request.
+ */
+static NSString *const kTokenKey = @"token";
+
+/** @var kReturnSecureTokenKey
+ @brief The key for the "returnSecureToken" value in the request.
+ */
+static NSString *const kReturnSecureTokenKey = @"returnSecureToken";
+
+@implementation FIRVerifyCustomTokenRequest
+
+- (nullable instancetype)initWithToken:(NSString *)token
+ APIKey:(NSString *)APIKey {
+ self = [super initWithEndpoint:kVerifyCustomTokenEndpoint APIKey:APIKey];
+ if (self) {
+ _token = [token copy];
+ _returnSecureToken = YES;
+ }
+ return self;
+}
+
+- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable)error {
+ NSMutableDictionary *body = [@{
+ kTokenKey : _token
+ } mutableCopy];
+ if (_returnSecureToken) {
+ body[kReturnSecureTokenKey] = @YES;
+ }
+ return body;
+}
+
+@end
diff --git a/Firebase/Auth/Source/RPCs/FIRVerifyCustomTokenResponse.h b/Firebase/Auth/Source/RPCs/FIRVerifyCustomTokenResponse.h
new file mode 100644
index 0000000..b8c215c
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRVerifyCustomTokenResponse.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "FIRAuthRPCResponse.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @class FIRVerifyCustomTokenResponse
+ @brief Represents the response from the verifyCustomToken endpoint.
+ */
+@interface FIRVerifyCustomTokenResponse : NSObject <FIRAuthRPCResponse>
+
+/** @property IDToken
+ @brief Either an authorization code suitable for performing an STS token exchange, or the
+ access token from Secure Token Service, depending on whether @c returnSecureToken is set
+ on the request.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *IDToken;
+
+/** @property approximateExpirationDate
+ @brief The approximate expiration date of the access token.
+ */
+@property(nonatomic, copy, readonly, nullable) NSDate *approximateExpirationDate;
+
+/** @property refreshToken
+ @brief The refresh token from Secure Token Service.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *refreshToken;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/RPCs/FIRVerifyCustomTokenResponse.m b/Firebase/Auth/Source/RPCs/FIRVerifyCustomTokenResponse.m
new file mode 100644
index 0000000..f86d94b
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRVerifyCustomTokenResponse.m
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRVerifyCustomTokenResponse.h"
+
+#import "../Private/FIRAuthErrorUtils.h"
+
+@implementation FIRVerifyCustomTokenResponse
+
+- (BOOL)setWithDictionary:(NSDictionary *)dictionary
+ error:(NSError *_Nullable *_Nullable)error {
+ _IDToken = [dictionary[@"idToken"] copy];
+ _approximateExpirationDate = [dictionary[@"expiresIn"] isKindOfClass:[NSString class]] ?
+ [NSDate dateWithTimeIntervalSinceNow:[dictionary[@"expiresIn"] doubleValue]] : nil;
+ _refreshToken = [dictionary[@"refreshToken"] copy];
+ return YES;
+}
+
+@end
diff --git a/Firebase/Auth/Source/RPCs/FIRVerifyPasswordRequest.h b/Firebase/Auth/Source/RPCs/FIRVerifyPasswordRequest.h
new file mode 100644
index 0000000..ba54bce
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRVerifyPasswordRequest.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "FIRAuthRPCRequest.h"
+#import "FIRIdentityToolkitRequest.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @class FIRVerifyPasswordRequest
+ @brief Represents the parameters for the verifyPassword endpoint.
+ @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/verifyPassword
+ */
+@interface FIRVerifyPasswordRequest : FIRIdentityToolkitRequest <FIRAuthRPCRequest>
+
+/** @property email
+ @brief The email of the user.
+ */
+@property(nonatomic, copy) NSString *email;
+
+/** @property password
+ @brief The password inputed by the user.
+ */
+@property(nonatomic, copy) NSString *password;
+
+/** @property pendingIDToken
+ @brief The GITKit token for the non-trusted IDP, which is to be confirmed by the user.
+ */
+@property(nonatomic, copy, nullable) NSString *pendingIDToken;
+
+/** @property captchaChallenge
+ @brief The captcha challenge.
+ */
+@property(nonatomic, copy, nullable) NSString *captchaChallenge;
+
+/** @property captchaResponse
+ @brief Response to the captcha.
+ */
+@property(nonatomic, copy, nullable) NSString *captchaResponse;
+
+/** @property returnSecureToken
+ @brief Whether the response should return access token and refresh token directly.
+ @remarks The default value is @c YES .
+ */
+@property(nonatomic, assign) BOOL returnSecureToken;
+
+/** @fn initWithEndpoint:APIKey:
+ @brief Please use initWithEmail:password:APIKey:
+ */
+- (nullable instancetype)initWithEndpoint:(NSString *)endpoint
+ APIKey:(NSString *)APIKey NS_UNAVAILABLE;
+
+/** @fn initWithEmail:password:APIKey:
+ @brief Designated initializer.
+ @param email The email of the user.
+ @param password The password inputed by the user.
+ @param APIKey The client's API Key.
+ */
+- (nullable instancetype)initWithEmail:(NSString *)email
+ password:(NSString *)password
+ APIKey:(NSString *)APIKey NS_DESIGNATED_INITIALIZER;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/RPCs/FIRVerifyPasswordRequest.m b/Firebase/Auth/Source/RPCs/FIRVerifyPasswordRequest.m
new file mode 100644
index 0000000..7a9da8b
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRVerifyPasswordRequest.m
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRVerifyPasswordRequest.h"
+
+/** @var kVerifyPasswordEndpoint
+ @brief The "verifyPassword" endpoint.
+ */
+static NSString *const kVerifyPasswordEndpoint = @"verifyPassword";
+
+/** @var kEmailKey
+ @brief The key for the "email" value in the request.
+ */
+static NSString *const kEmailKey = @"email";
+
+/** @var kPasswordKey
+ @brief The key for the "password" value in the request.
+ */
+static NSString *const kPasswordKey = @"password";
+
+/** @var kPendingIDTokenKey
+ @brief The key for the "pendingIdToken" value in the request.
+ */
+static NSString *const kPendingIDTokenKey = @"pendingIdToken";
+
+/** @var kCaptchaChallengeKey
+ @brief The key for the "captchaChallenge" value in the request.
+ */
+static NSString *const kCaptchaChallengeKey = @"captchaChallenge";
+
+/** @var kCaptchaResponseKey
+ @brief The key for the "captchaResponse" value in the request.
+ */
+static NSString *const kCaptchaResponseKey = @"captchaResponse";
+
+/** @var kReturnSecureTokenKey
+ @brief The key for the "returnSecureToken" value in the request.
+ */
+static NSString *const kReturnSecureTokenKey = @"returnSecureToken";
+
+@implementation FIRVerifyPasswordRequest
+
+- (nullable instancetype)initWithEmail:(NSString *)email
+ password:(NSString *)password
+ APIKey:(NSString *)APIKey {
+ self = [super initWithEndpoint:kVerifyPasswordEndpoint APIKey:APIKey];
+ if (self) {
+ _email = [email copy];
+ _password = [password copy];
+ _returnSecureToken = YES;
+ }
+ return self;
+}
+
+- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable)error {
+ NSMutableDictionary *postBody = [NSMutableDictionary dictionary];
+ if (_email) {
+ postBody[kEmailKey] = _email;
+ }
+ if (_password) {
+ postBody[kPasswordKey] = _password;
+ }
+ if (_pendingIDToken) {
+ postBody[kPendingIDTokenKey] = _pendingIDToken;
+ }
+ if (_captchaChallenge) {
+ postBody[kCaptchaChallengeKey] = _captchaChallenge;
+ }
+ if (_captchaResponse) {
+ postBody[kCaptchaResponseKey] = _captchaResponse;
+ }
+ if (_returnSecureToken) {
+ postBody[kReturnSecureTokenKey] = @YES;
+ }
+ return postBody;
+}
+
+@end
diff --git a/Firebase/Auth/Source/RPCs/FIRVerifyPasswordResponse.h b/Firebase/Auth/Source/RPCs/FIRVerifyPasswordResponse.h
new file mode 100644
index 0000000..bed13be
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRVerifyPasswordResponse.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "FIRAuthRPCResponse.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @class FIRVerifyPasswordResponse
+ @brief Represents the response from the verifyPassword endpoint.
+ @remarks Possible error codes:
+ - FIRAuthInternalErrorCodeUserDisabled
+ - FIRAuthInternalErrorCodeEmailNotFound
+ @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/verifyPassword
+ */
+@interface FIRVerifyPasswordResponse : NSObject <FIRAuthRPCResponse>
+
+/** @property localID
+ @brief The RP local ID if it's already been mapped to the IdP account identified by the
+ federated ID.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *localID;
+
+/** @property email
+ @brief The email returned by the IdP. NOTE: The federated login user may not own the email.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *email;
+
+/** @property displayName
+ @brief The display name of the user.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *displayName;
+
+/** @property IDToken
+ @brief Either an authorization code suitable for performing an STS token exchange, or the
+ access token from Secure Token Service, depending on whether @c returnSecureToken is set
+ on the request.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *IDToken;
+
+/** @property approximateExpirationDate
+ @brief The approximate expiration date of the access token.
+ */
+@property(nonatomic, copy, readonly, nullable) NSDate *approximateExpirationDate;
+
+/** @property refreshToken
+ @brief The refresh token from Secure Token Service.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *refreshToken;
+
+/** @property photoURL
+ @brief The URI of the public accessible profile picture.
+ */
+@property(nonatomic, strong, readonly, nullable) NSURL *photoURL;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/RPCs/FIRVerifyPasswordResponse.m b/Firebase/Auth/Source/RPCs/FIRVerifyPasswordResponse.m
new file mode 100644
index 0000000..4d0ca10
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRVerifyPasswordResponse.m
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRVerifyPasswordResponse.h"
+
+#import "../Private/FIRAuthErrorUtils.h"
+
+@implementation FIRVerifyPasswordResponse
+
+- (BOOL)setWithDictionary:(NSDictionary *)dictionary
+ error:(NSError *_Nullable *_Nullable)error {
+ _localID = [dictionary[@"localId"] copy];
+ _email = [dictionary[@"email"] copy];
+ _displayName = [dictionary[@"displayName"] copy];
+ _IDToken = [dictionary[@"idToken"] copy];
+ _approximateExpirationDate = [dictionary[@"expiresIn"] isKindOfClass:[NSString class]] ?
+ [NSDate dateWithTimeIntervalSinceNow:[dictionary[@"expiresIn"] doubleValue]] : nil;
+ _refreshToken = [dictionary[@"refreshToken"] copy];
+ _photoURL = dictionary[@"photoUrl"] ? [NSURL URLWithString:dictionary[@"photoUrl"]] : nil;
+ return YES;
+}
+
+@end
diff --git a/Firebase/Auth/Source/RPCs/FIRVerifyPhoneNumberRequest.h b/Firebase/Auth/Source/RPCs/FIRVerifyPhoneNumberRequest.h
new file mode 100644
index 0000000..06039b9
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRVerifyPhoneNumberRequest.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRIdentityToolkitRequest.h"
+
+#import "FIRAuthRPCRequest.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface FIRVerifyPhoneNumberRequest : FIRIdentityToolkitRequest <FIRAuthRPCRequest>
+
+/** @property verificationID
+ @brief The verification ID obtained from the response of @c sendVerificationCode.
+*/
+@property(nonatomic, readonly, nullable) NSString *verificationID;
+
+/** @property verificationCode
+ @brief The verification code provided by the user.
+*/
+@property(nonatomic, readonly, nullable) NSString *verificationCode;
+
+/** @property accessToken
+ @brief The STS Access Token for the authenticated user.
+ */
+@property(nonatomic, copy, nullable) NSString *accessToken;
+
+/** @var temporaryProof
+ @brief The a temporary proof code pertaining to this credentil, returned from the backend.
+ */
+@property(nonatomic, readonly, nonnull) NSString *temporaryProof;
+
+/** @var phoneNumber
+ @brief The a phone number pertaining to this credential, returned from the backend.
+ */
+@property(nonatomic, readonly, nonnull) NSString *phoneNumber;
+
+/** @fn initWithEndpoint:APIKey:
+ @brief Please use initWithPhoneNumber:APIKey:
+ */
+- (nullable instancetype)initWithEndpoint:(NSString *)endpoint
+ APIKey:(NSString *)APIKey NS_UNAVAILABLE;
+
+/** @fn initWithTemporaryProof:phoneNumberAPIKey
+ @brief Designated initializer.
+ @param temporaryProof The temporary proof sent by the backed.
+ @param phoneNumber The phone number associated with the credential to be signed in.
+ @param APIKey The client's API Key.
+ */
+- (nullable instancetype)initWithTemporaryProof:(NSString *)temporaryProof
+ phoneNumber:(NSString *)phoneNumber
+ APIKey:(NSString *)APIKey NS_DESIGNATED_INITIALIZER;
+
+/** @fn initWithVerificationID:verificationCode:APIKey
+ @brief Designated initializer.
+ @param verificationID The verification ID obtained from the response of @c sendVerificationCode.
+ @param verificationCode The verification code provided by the user.
+ @param APIKey The client's API Key.
+ */
+- (nullable instancetype)initWithVerificationID:(NSString *)verificationID
+ verificationCode:(NSString *)verificationCode
+ APIKey:(NSString *)APIKey NS_DESIGNATED_INITIALIZER;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/RPCs/FIRVerifyPhoneNumberRequest.m b/Firebase/Auth/Source/RPCs/FIRVerifyPhoneNumberRequest.m
new file mode 100644
index 0000000..b3d1054
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRVerifyPhoneNumberRequest.m
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRVerifyPhoneNumberRequest.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @var kVerifyPhoneNumberEndPoint
+ @brief The "verifyPhoneNumber" endpoint.
+ */
+static NSString *const kVerifyPhoneNumberEndPoint = @"verifyPhoneNumber";
+
+/** @var kVerificationIDKey
+ @brief The key for the verification ID parameter in the request.
+ */
+static NSString *const kVerificationIDKey = @"sessionInfo";
+
+/** @var kVerificationCodeKey
+ @brief The key for the verification code parameter in the request.
+ */
+static NSString *const kVerificationCodeKey = @"code";
+
+/** @var kIDTokenKey
+ @brief The key for the "ID Token" value in the request.
+ */
+static NSString *const kIDTokenKey = @"idToken";
+
+/** @var kTemporaryProofKey
+ @brief The key for the temporary proof value in the request.
+ */
+static NSString *const kTemporaryProofKey = @"temporaryProof";
+
+/** @var kPhoneNumberKey
+ @brief The key for the phone number value in the request.
+ */
+static NSString *const kPhoneNumberKey = @"phoneNumber";
+
+@implementation FIRVerifyPhoneNumberRequest
+
+- (nullable instancetype)initWithTemporaryProof:(NSString *)temporaryProof
+ phoneNumber:(NSString *)phoneNumber
+ APIKey:(NSString *)APIKey {
+ self = [super initWithEndpoint:kVerifyPhoneNumberEndPoint APIKey:APIKey];
+ if (self) {
+ _temporaryProof = [temporaryProof copy];
+ _phoneNumber = [phoneNumber copy];
+ }
+ return self;
+}
+
+- (nullable instancetype)initWithVerificationID:(NSString *)verificationID
+ verificationCode:(NSString *)verificationCode
+ APIKey:(NSString *)APIKey {
+ self = [super initWithEndpoint:kVerifyPhoneNumberEndPoint APIKey:APIKey];
+ if (self) {
+ _verificationID = verificationID;
+ _verificationCode = verificationCode;
+ }
+ return self;
+}
+
+- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *__autoreleasing _Nullable *)error {
+ NSMutableDictionary *postBody = [NSMutableDictionary dictionary];
+ if (_verificationID) {
+ postBody[kVerificationIDKey] = _verificationID;
+ }
+ if (_verificationCode) {
+ postBody[kVerificationCodeKey] = _verificationCode;
+ }
+ if (_accessToken) {
+ postBody[kIDTokenKey] = _accessToken;
+ }
+ if (_temporaryProof) {
+ postBody[kTemporaryProofKey] = _temporaryProof;
+ }
+ if (_phoneNumber) {
+ postBody[kPhoneNumberKey] = _phoneNumber;
+ }
+ return postBody;
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/RPCs/FIRVerifyPhoneNumberResponse.h b/Firebase/Auth/Source/RPCs/FIRVerifyPhoneNumberResponse.h
new file mode 100644
index 0000000..f8f4ba2
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRVerifyPhoneNumberResponse.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "FIRAuthRPCResponse.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface FIRVerifyPhoneNumberResponse : NSObject <FIRAuthRPCResponse>
+
+/** @property IDToken
+ @brief Either an authorization code suitable for performing an STS token exchange, or the
+ access token from Secure Token Service, depending on whether @c returnSecureToken is set
+ on the request.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *IDToken;
+
+/** @property refreshToken
+ @brief The refresh token from Secure Token Service.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *refreshToken;
+
+/** @property localID
+ @brief The Firebear user ID.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *localID;
+
+/** @property phoneNumber
+ @brief The verified phone number.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *phoneNumber;
+
+/** @property temporaryProof
+ @brief The temporary proof code returned by the backend.
+ */
+@property(nonatomic, strong, readonly, nullable) NSString *temporaryProof;
+
+/** @property isNewUser
+ @brief Flag indicating that the user signing in is a new user and not a returning user.
+ */
+@property(nonatomic, assign) BOOL isNewUser;
+
+/** @property approximateExpirationDate
+ @brief The approximate expiration date of the access token.
+ */
+@property(nonatomic, copy, readonly, nullable) NSDate *approximateExpirationDate;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firebase/Auth/Source/RPCs/FIRVerifyPhoneNumberResponse.m b/Firebase/Auth/Source/RPCs/FIRVerifyPhoneNumberResponse.m
new file mode 100644
index 0000000..acba2c2
--- /dev/null
+++ b/Firebase/Auth/Source/RPCs/FIRVerifyPhoneNumberResponse.m
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRVerifyPhoneNumberResponse.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@implementation FIRVerifyPhoneNumberResponse
+
+- (nullable NSString *)expectedKind {
+ return nil;
+}
+
+- (BOOL)setWithDictionary:(NSDictionary *)dictionary
+ error:(NSError *_Nullable *_Nullable)error {
+ _IDToken = [dictionary[@"idToken"] copy];
+ _refreshToken = [dictionary[@"refreshToken"] copy];
+ _isNewUser = [dictionary[@"isNewUser"] boolValue];
+ _localID = [dictionary[@"localId"] copy];
+ _phoneNumber = [dictionary[@"phoneNumber"] copy];
+ _temporaryProof = [dictionary[@"temporaryProof"] copy];
+ _approximateExpirationDate = [dictionary[@"expiresIn"] isKindOfClass:[NSString class]] ?
+ [NSDate dateWithTimeIntervalSinceNow:[dictionary[@"expiresIn"] doubleValue]] : nil;
+ return YES;
+}
+
+@end
+
+NS_ASSUME_NONNULL_END