aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Ryan Wilson <wilsonryan@google.com>2018-07-11 17:40:25 -0400
committerGravatar GitHub <noreply@github.com>2018-07-11 17:40:25 -0400
commit79f663d5eaaa4b7f9fe46d176c82660d38e4be8a (patch)
tree47b27cb93aa0372eb141668526552b3559ac1dbb
parentc6b4b03fffc3cea7c9525e5c79dce28f52900521 (diff)
Add Auth interoperability library. (#1501)
* Add Auth interoperability library. This allows other SDKs to retrieve the user ID and fetch a new Auth token in a type-safe way through the Core container. * Remove unnecessary import. * Add missing copyright. * Resolve comments. - Remove unnecessary umbrella header. - Move to version 1.0. - Add tvOS support for app lifecycle changes. * Move public interop headers to private. * Add public_header_files too. * Moved headers back into public. * Shorten Interoperability and Interoperable to Interop. * Add AuthInterop to travis linting. * Fixed tag format in AuthInterop.podspec. * Add AuthInterop path to Firestore Podfile.
-rw-r--r--.travis.yml2
-rw-r--r--Example/Auth/Tests/FIRAuthTests.m25
-rw-r--r--Example/Core/Tests/FIRAppTest.m1
-rw-r--r--Example/Podfile1
-rw-r--r--Firebase/Auth/Source/FIRAuth.m222
-rw-r--r--Firebase/Auth/Source/FIRAuth_Internal.h4
-rw-r--r--Firebase/Auth/Source/FIRUser.m2
-rw-r--r--Firebase/Core/FIRApp.m1
-rw-r--r--FirebaseAuth.podspec1
-rw-r--r--FirebaseAuthInterop.podspec29
-rw-r--r--Firestore/Example/Podfile1
-rw-r--r--Interop/Auth/Public/FIRAuthInterop.h42
12 files changed, 233 insertions, 98 deletions
diff --git a/.travis.yml b/.travis.yml
index 79903c7..59ba692 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -64,6 +64,7 @@ jobs:
- ./scripts/if_changed.sh bundle exec pod lib lint GoogleUtilities.podspec
- ./scripts/if_changed.sh bundle exec pod lib lint FirebaseCore.podspec $ALT_SOURCES
- ./scripts/if_changed.sh bundle exec pod lib lint FirebaseAuth.podspec $ALT_SOURCES
+ - ./scripts/if_changed.sh bundle exec pod lib lint FirebaseAuthInterop.podspec $ALT_SOURCES
- ./scripts/if_changed.sh bundle exec pod lib lint FirebaseDatabase.podspec $ALT_SOURCES
- ./scripts/if_changed.sh bundle exec pod lib lint FirebaseMessaging.podspec $ALT_SOURCES
- ./scripts/if_changed.sh bundle exec pod lib lint FirebaseStorage.podspec $ALT_SOURCES
@@ -90,6 +91,7 @@ jobs:
script:
- ./scripts/if_cron.sh bundle exec pod lib lint FirebaseCore.podspec --use-libraries $ALT_SOURCES
- ./scripts/if_cron.sh bundle exec pod lib lint FirebaseAuth.podspec --use-libraries $ALT_SOURCES
+ - ./scripts/if_cron.sh bundle exec pod lib lint FirebaseAuthInterop.podspec --use-libraries $ALT_SOURCES
- ./scripts/if_cron.sh bundle exec pod lib lint FirebaseDatabase.podspec --use-libraries $ALT_SOURCES
# The Protobuf dependency of FirebaseMessaging has warnings with --use-libraries
- ./scripts/if_cron.sh bundle exec pod lib lint FirebaseMessaging.podspec --use-libraries --allow-warnings $ALT_SOURCES
diff --git a/Example/Auth/Tests/FIRAuthTests.m b/Example/Auth/Tests/FIRAuthTests.m
index 6a047a4..c008bab 100644
--- a/Example/Auth/Tests/FIRAuthTests.m
+++ b/Example/Auth/Tests/FIRAuthTests.m
@@ -18,7 +18,11 @@
#import <XCTest/XCTest.h>
+#import <FirebaseAuth/FirebaseAuth.h>
+#import <FirebaseAuthInterop/FIRAuthInterop.h>
#import <FirebaseCore/FIRAppInternal.h>
+#import <FirebaseCore/FIRComponent.h>
+#import <FirebaseCore/FIRComponentRegistrant.h>
#import "FIRAdditionalUserInfo.h"
#import "FIRAuth_Internal.h"
@@ -221,6 +225,10 @@ static const NSTimeInterval kExpectationTimeout = 2;
*/
static const NSTimeInterval kWaitInterval = .5;
+/** Category for FIRAuth to expose FIRComponentRegistrant conformance. */
+@interface FIRAuth () <FIRComponentRegistrant>
+@end
+
/** @class FIRAuthTests
@brief Tests for @c FIRAuth.
*/
@@ -362,6 +370,8 @@ static const NSTimeInterval kWaitInterval = .5;
@brief Verifies that FIRApp's getUIDImplementation is correctly set by FIRAuth.
*/
- (void)testGetUID {
+ // TODO: Remove this test once Firestore, Database, and Storage move over to the new Auth interop
+ // library.
FIRApp *app = [FIRApp defaultApp];
XCTAssertNotNil(app.getUIDImplementation);
[[FIRAuth auth] signOut:NULL];
@@ -2221,6 +2231,21 @@ static const NSTimeInterval kWaitInterval = .5;
}
#endif
+#pragma mark - Interoperability Tests
+
+/** @fn testComponentsBeingRegistered
+ @brief Tests that Auth provides the necessary components for interoperability with other SDKs.
+ */
+- (void)testComponentsBeingRegistered {
+ // Verify that the components are registered properly. Check the count, because any time a new
+ // component is added it should be added to the test suite as well.
+ NSArray<FIRComponent *> *components = [FIRAuth componentsToRegister];
+ XCTAssertTrue(components.count == 1);
+
+ FIRComponent *component = [components firstObject];
+ XCTAssert(component.protocol == @protocol(FIRAuthInterop));
+}
+
#pragma mark - Helpers
/** @fn mockSecureTokenResponseWithError:
diff --git a/Example/Core/Tests/FIRAppTest.m b/Example/Core/Tests/FIRAppTest.m
index 656f046..d88ed66 100644
--- a/Example/Core/Tests/FIRAppTest.m
+++ b/Example/Core/Tests/FIRAppTest.m
@@ -754,6 +754,7 @@ NSString *const kFIRTestAppName2 = @"test-app-name-2";
#pragma mark - Internal Methods
+// TODO: Remove this test once the `getUIDImplementation` block doesn't need to be set in Core.
- (void)testAuthGetUID {
[FIRApp configure];
diff --git a/Example/Podfile b/Example/Podfile
index dc3acd0..373471f 100644
--- a/Example/Podfile
+++ b/Example/Podfile
@@ -4,6 +4,7 @@
use_frameworks!
+pod 'FirebaseAuthInterop', :path => '../'
pod 'FirebaseCore', :path => '../'
pod 'GoogleUtilities', :path => '../'
diff --git a/Firebase/Auth/Source/FIRAuth.m b/Firebase/Auth/Source/FIRAuth.m
index 691c6ce..b353ebb 100644
--- a/Firebase/Auth/Source/FIRAuth.m
+++ b/Firebase/Auth/Source/FIRAuth.m
@@ -18,8 +18,17 @@
#import "FIRAuth_Internal.h"
+#if __has_include(<UIKit/UIKit.h>)
+#import <UIKit/UIKit.h>
+#endif
+
+#import <FirebaseAuthInterop/FIRAuthInterop.h>
#import <FirebaseCore/FIRAppAssociationRegistration.h>
#import <FirebaseCore/FIRAppInternal.h>
+#import <FirebaseCore/FIRComponent.h>
+#import <FirebaseCore/FIRComponentContainer.h>
+#import <FirebaseCore/FIRComponentRegistrant.h>
+#import <FirebaseCore/FIRCoreConfigurable.h>
#import <FirebaseCore/FIRLogger.h>
#import <FirebaseCore/FIROptions.h>
#import <GoogleUtilities/GULAppEnvironmentUtil.h>
@@ -63,7 +72,6 @@
#import "FIRVerifyPhoneNumberResponse.h"
#if TARGET_OS_IOS
-#import <UIKit/UIKit.h>
#import "FIRAuthAPNSToken.h"
#import "FIRAuthAPNSTokenManager.h"
#import "FIRAuthAppCredentialManager.h"
@@ -218,9 +226,9 @@ static NSMutableDictionary *gKeychainServiceNameForAppName;
#pragma mark - FIRAuth
#if TARGET_OS_IOS
-@interface FIRAuth () <FIRAuthAppDelegateHandler>
+@interface FIRAuth () <FIRAuthAppDelegateHandler, FIRAuthInterop, FIRComponentRegistrant, FIRCoreConfigurable, FIRComponentLifecycleMaintainer>
#else
-@interface FIRAuth ()
+@interface FIRAuth () <FIRAuthInterop, FIRComponentRegistrant, FIRCoreConfigurable, FIRComponentLifecycleMaintainer>
#endif
/** @property firebaseAppId
@@ -300,42 +308,12 @@ static NSMutableDictionary *gKeychainServiceNameForAppName;
}
+ (void)load {
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- gKeychainServiceNameForAppName = [[NSMutableDictionary alloc] init];
-
- NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
+ [FIRComponentContainer registerAsComponentRegistrant:self];
+ [FIRApp registerAsConfigurable:self];
+}
- // 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];
- });
- });
- }];
- });
++ (void)initialize {
+ gKeychainServiceNameForAppName = [[NSMutableDictionary alloc] init];
}
+ (FIRAuth *)auth {
@@ -352,11 +330,10 @@ static NSMutableDictionary *gKeychainServiceNameForAppName;
}
+ (FIRAuth *)authWithApp:(FIRApp *)app {
- return [FIRAppAssociationRegistration registeredObjectWithHost:app
- key:NSStringFromClass(self)
- creationBlock:^FIRAuth *_Nullable() {
- return [[FIRAuth alloc] initWithApp:app];
- }];
+ // Get the instance of Auth from the container, which will create or return the cached instance
+ // associated with this app.
+ id<FIRAuthInterop> auth = FIR_COMPONENT(FIRAuthInterop, app.container);
+ return (FIRAuth *)auth;
}
- (instancetype)initWithApp:(FIRApp *)app {
@@ -365,62 +342,19 @@ static NSMutableDictionary *gKeychainServiceNameForAppName;
if (self) {
_app = app;
__weak FIRAuth *weakSelf = self;
+
+ // TODO: Remove this block once Firestore, Database, and Storage move to the new interop API.
app.getTokenImplementation = ^(BOOL forceRefresh, FIRTokenCallback callback) {
- dispatch_async(FIRAuthGlobalWorkQueue(), ^{
- FIRAuth *strongSelf = weakSelf;
- // Enable token auto-refresh if not aleady enabled.
- if (strongSelf && !strongSelf->_autoRefreshTokens) {
- FIRLogInfo(kFIRLoggerAuth, @"I-AUT000002", @"Token auto-refresh enabled.");
- strongSelf->_autoRefreshTokens = YES;
- [strongSelf scheduleAutoTokenRefresh];
-
- #if TARGET_OS_IOS // TODO: Is a similar mechanism needed on macOS?
- 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;
- }
- }];
- #endif
- }
- // Call back with 'nil' if there is no current user.
- if (!strongSelf || !strongSelf->_currentUser) {
- dispatch_async(dispatch_get_main_queue(), ^{
- callback(nil, nil);
- });
- return;
- }
- // Call back with current user token.
- [strongSelf->_currentUser internalGetTokenForcingRefresh:forceRefresh
- callback:^(NSString *_Nullable token,
- NSError *_Nullable error) {
- dispatch_async(dispatch_get_main_queue(), ^{
- callback(token, error);
- });
- }];
- });
+ // In the meantime, redirect call to the interop method that provides this functionality.
+ __weak FIRAuth *weakSelf = self;
+ [weakSelf getTokenForcingRefresh:forceRefresh withCallback:callback];
};
+
+ // TODO: Remove this block once Firestore, Database, and Storage move to the new interop API.
app.getUIDImplementation = ^NSString *_Nullable() {
__block NSString *uid;
dispatch_sync(FIRAuthGlobalWorkQueue(), ^{
- uid = [weakSelf getUID];
+ uid = [weakSelf getUserID];
});
return uid;
};
@@ -1878,7 +1812,105 @@ static NSDictionary<NSString *, NSString *> *FIRAuthParseURL(NSString *urlString
return YES;
}
-- (nullable NSString *)getUID {
+#pragma mark - Interoperability
+
++ (nonnull NSArray<FIRComponent *> *)componentsToRegister {
+ FIRComponentCreationBlock authCreationBlock =
+ ^id _Nullable(FIRComponentContainer *_Nonnull container, BOOL *_Nonnull isCacheable) {
+ *isCacheable = YES;
+ return [[FIRAuth alloc] initWithApp:container.app];
+ };
+ FIRComponent *authInterop = [FIRComponent componentWithProtocol:@protocol(FIRAuthInterop)
+ creationBlock:authCreationBlock];
+ return @[authInterop];
+}
+
+#pragma mark - FIRCoreConfigurable
+
++ (void)configureWithApp:(nonnull FIRApp *)app {
+ // TODO: Evaluate what actually needs to be configured here instead of initializing a full
+ // instance.
+ // Ensures the @c FIRAuth instance for a given app gets loaded as soon as the app is ready.
+ [FIRAuth authWithApp:app];
+}
+
+#pragma mark - FIRComponentLifecycleMaintainer
+
+- (void)appWillBeDeleted:(nonnull FIRApp *)app {
+ dispatch_async(FIRAuthGlobalWorkQueue(), ^{
+ // This doesn't stop any request already issued, see b/27704535 .
+ NSString *keychainServiceName = [FIRAuth keychainServiceNameForAppName:app.name];
+ if (keychainServiceName) {
+ [[self class] deleteKeychainServiceNameForAppName:app.name];
+ FIRAuthKeychain *keychain = [[FIRAuthKeychain alloc] initWithService:keychainServiceName];
+ NSString *userKey = [NSString stringWithFormat:kUserKey, app.name];
+ [keychain removeDataForKey:userKey error:NULL];
+ }
+ dispatch_async(dispatch_get_main_queue(), ^{
+ // TODO: Move over to fire an event instead, once ready.
+ [[NSNotificationCenter defaultCenter] postNotificationName:FIRAuthStateDidChangeNotification
+ object:nil];
+ });
+ });
+}
+
+#pragma mark - FIRAuthInterop
+
+- (void)getTokenForcingRefresh:(BOOL)forceRefresh withCallback:(FIRTokenCallback)callback {
+ __weak FIRAuth *weakSelf = self;
+ dispatch_async(FIRAuthGlobalWorkQueue(), ^{
+ FIRAuth *strongSelf = weakSelf;
+ // Enable token auto-refresh if not aleady enabled.
+ if (strongSelf && !strongSelf->_autoRefreshTokens) {
+ FIRLogInfo(kFIRLoggerAuth, @"I-AUT000002", @"Token auto-refresh enabled.");
+ strongSelf->_autoRefreshTokens = YES;
+ [strongSelf scheduleAutoTokenRefresh];
+
+#if TARGET_OS_IOS || TARGET_OS_TV // TODO: Is a similar mechanism needed on macOS?
+ 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;
+ }
+ }];
+#endif
+ }
+ // Call back with 'nil' if there is no current user.
+ if (!strongSelf || !strongSelf->_currentUser) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ callback(nil, nil);
+ });
+ return;
+ }
+ // Call back with current user token.
+ [strongSelf->_currentUser internalGetTokenForcingRefresh:forceRefresh
+ callback:^(NSString *_Nullable token,
+ NSError *_Nullable error) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ callback(token, error);
+ });
+ }];
+ });
+}
+
+- (nullable NSString *)getUserID {
return _currentUser.uid;
}
diff --git a/Firebase/Auth/Source/FIRAuth_Internal.h b/Firebase/Auth/Source/FIRAuth_Internal.h
index 4d87a08..519ece3 100644
--- a/Firebase/Auth/Source/FIRAuth_Internal.h
+++ b/Firebase/Auth/Source/FIRAuth_Internal.h
@@ -69,11 +69,11 @@ NS_ASSUME_NONNULL_BEGIN
- (nullable instancetype)initWithAPIKey:(NSString *)APIKey
appName:(NSString *)appName NS_DESIGNATED_INITIALIZER;
-/** @fn getUID
+/** @fn getUserID
@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;
+- (nullable NSString *)getUserID;
/** @fn updateKeychainWithUser:error:
@brief Updates the keychain for the given user.
diff --git a/Firebase/Auth/Source/FIRUser.m b/Firebase/Auth/Source/FIRUser.m
index ad0b1d4..f3832a7 100644
--- a/Firebase/Auth/Source/FIRUser.m
+++ b/Firebase/Auth/Source/FIRUser.m
@@ -766,7 +766,7 @@ static void callInMainThreadWithAuthDataResultAndError(
callInMainThreadWithAuthDataResultAndError(completion, authResult, error);
return;
}
- if (![authResult.user.uid isEqual:[self->_auth getUID]]) {
+ if (![authResult.user.uid isEqual:[self->_auth getUserID]]) {
callInMainThreadWithAuthDataResultAndError(completion, authResult,
[FIRAuthErrorUtils userMismatchError]);
return;
diff --git a/Firebase/Core/FIRApp.m b/Firebase/Core/FIRApp.m
index 9f698cf..5fca127 100644
--- a/Firebase/Core/FIRApp.m
+++ b/Firebase/Core/FIRApp.m
@@ -517,6 +517,7 @@ static NSMutableDictionary *sLibraryVersions;
}
}
+// TODO: Remove once SDKs transition to Auth interop library.
- (nullable NSString *)getUID {
if (!_getUIDImplementation) {
FIRLogWarning(kFIRLoggerCore, @"I-COR000025", @"FIRAuth getUID implementation wasn't set.");
diff --git a/FirebaseAuth.podspec b/FirebaseAuth.podspec
index 47e211b..b08d830 100644
--- a/FirebaseAuth.podspec
+++ b/FirebaseAuth.podspec
@@ -61,6 +61,7 @@ supports email and password accounts, as well as several 3rd party authenticatio
}
s.framework = 'SafariServices'
s.framework = 'Security'
+ s.dependency 'FirebaseAuthInterop', '~> 1.0'
s.dependency 'FirebaseCore', '~> 5.0'
s.dependency 'GoogleUtilities/Environment', '~> 5.0'
s.dependency 'GTMSessionFetcher/Core', '~> 1.1'
diff --git a/FirebaseAuthInterop.podspec b/FirebaseAuthInterop.podspec
new file mode 100644
index 0000000..598db1a
--- /dev/null
+++ b/FirebaseAuthInterop.podspec
@@ -0,0 +1,29 @@
+Pod::Spec.new do |s|
+ s.name = 'FirebaseAuthInterop'
+ s.version = '1.0.0'
+ s.summary = 'Interfaces that allow other Firebase SDKs to use Auth functionality.'
+
+ s.description = <<-DESC
+ INTERNAL ONLY: A set of protocols that other Firebase SDKs can use to interoperate with Auth in a
+ safe and reliable manner.
+ DESC
+
+ s.homepage = 'https://firebase.google.com'
+ s.license = { :type => 'Apache', :file => 'LICENSE' }
+ s.authors = 'Google, Inc.'
+
+ # NOTE that these should not be used externally, this is for Firebase pods to depend on each
+ # other.
+ s.source = {
+ :git => 'https://github.com/firebase/firebase-ios-sdk.git',
+# TODO: Remove this once it is merged in master and ready for release in M30.
+# :tag => 'AuthInterop-' + s.version.to_s
+ :tag => 'pre-AuthInterop-' + s.version.to_s
+ }
+ s.social_media_url = 'https://twitter.com/Firebase'
+ s.ios.deployment_target = '8.0'
+ s.osx.deployment_target = '10.10'
+ s.tvos.deployment_target = '10.0'
+ s.source_files = 'Interop/Auth/**/*.h'
+ s.public_header_files = 'Interop/Auth/Public/*.h'
+end
diff --git a/Firestore/Example/Podfile b/Firestore/Example/Podfile
index 86cbd82..cde5780 100644
--- a/Firestore/Example/Podfile
+++ b/Firestore/Example/Podfile
@@ -13,6 +13,7 @@ target 'Firestore_Example_iOS' do
pod 'Firebase/CoreOnly', '5.4.0'
pod 'FirebaseAuth', :path => '../../'
+ pod 'FirebaseAuthInterop', :path => '../../'
pod 'FirebaseCore', :path => '../../'
pod 'GoogleUtilities', :path => '../../'
pod 'FirebaseFirestore', :path => '../../'
diff --git a/Interop/Auth/Public/FIRAuthInterop.h b/Interop/Auth/Public/FIRAuthInterop.h
new file mode 100644
index 0000000..5c365a3
--- /dev/null
+++ b/Interop/Auth/Public/FIRAuthInterop.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2018 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 FIRAuthInterop_h
+#define FIRAuthInterop_h
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @typedef FIRTokenCallback
+ @brief The type of block which gets called when a token is ready.
+ */
+typedef void (^FIRTokenCallback)(NSString *_Nullable token, NSError *_Nullable error)
+ NS_SWIFT_NAME(TokenCallback);
+
+/// Common methods for Auth interoperability.
+NS_SWIFT_NAME(AuthInterop)
+@protocol FIRAuthInterop
+
+/// Retrieves the Firebase authentication token, possibly refreshing it if it has expired.
+- (void)getTokenForcingRefresh:(BOOL)forceRefresh withCallback:(FIRTokenCallback)callback;
+
+/// Get the current Auth user's UID. Returns nil if there is no user signed in.
+- (nullable NSString *)getUserID;
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+#endif /* FIRAuthInterop_h */