Skip to content

Commit ae854d8

Browse files
authored
Sync login state across all Apple user's devices (#6924)
* shareLoginAcrossDevices * shareLoginAcrossDevices * shareLoginAcrossDevices * shareLoginAcrossDevices * formatting * feedback changes * linted
1 parent 8864ff9 commit ae854d8

File tree

4 files changed

+59
-16
lines changed

4 files changed

+59
-16
lines changed

FirebaseAuth/Sources/Auth/FIRAuth.m

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2020,12 +2020,15 @@ - (BOOL)saveUser:(nullable FIRUser *)user error:(NSError *_Nullable *_Nullable)o
20202020
}
20212021
} else {
20222022
if (!user) {
2023-
success = [self.storedUserManager removeStoredUserForAccessGroup:self.userAccessGroup
2024-
projectIdentifier:self.app.options.APIKey
2025-
error:outError];
2023+
success =
2024+
[self.storedUserManager removeStoredUserForAccessGroup:self.userAccessGroup
2025+
shareAuthStateAcrossDevices:self.shareAuthStateAcrossDevices
2026+
projectIdentifier:self.app.options.APIKey
2027+
error:outError];
20262028
} else {
20272029
success = [self.storedUserManager setStoredUser:user
20282030
forAccessGroup:self.userAccessGroup
2031+
shareAuthStateAcrossDevices:self.shareAuthStateAcrossDevices
20292032
projectIdentifier:self.app.options.APIKey
20302033
error:outError];
20312034
}
@@ -2077,9 +2080,11 @@ - (BOOL)getUser:(FIRUser *_Nullable *)outUser error:(NSError *_Nullable *_Nullab
20772080

20782081
return YES;
20792082
} else {
2080-
FIRUser *user = [self.storedUserManager getStoredUserForAccessGroup:self.userAccessGroup
2081-
projectIdentifier:self.app.options.APIKey
2082-
error:error];
2083+
FIRUser *user =
2084+
[self.storedUserManager getStoredUserForAccessGroup:self.userAccessGroup
2085+
shareAuthStateAcrossDevices:self.shareAuthStateAcrossDevices
2086+
projectIdentifier:self.app.options.APIKey
2087+
error:error];
20832088
user.auth = self;
20842089
*outUser = user;
20852090
if (user) {
@@ -2254,6 +2259,7 @@ - (nullable FIRUser *)getStoredUserForAccessGroup:(NSString *_Nullable)accessGro
22542259
user = [unarchiver decodeObjectOfClass:[FIRUser class] forKey:userKey];
22552260
} else {
22562261
user = [self.storedUserManager getStoredUserForAccessGroup:self.userAccessGroup
2262+
shareAuthStateAcrossDevices:self.shareAuthStateAcrossDevices
22572263
projectIdentifier:self.app.options.APIKey
22582264
error:outError];
22592265
}

FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuth.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,14 @@ NS_SWIFT_NAME(Auth)
340340
*/
341341
@property(readonly, nonatomic, copy, nullable) NSString *userAccessGroup;
342342

343+
/** @property shareAuthStateAcrossDevices
344+
@brief Contains shareAuthStateAcrossDevices setting related to the auth object.
345+
@remarks If userAccessGroup is not set, setting shareAuthStateAcrossDevices will
346+
have no effect. You should set shareAuthStateAcrossDevices to it's desired
347+
state and then set the userAccessGroup after.
348+
*/
349+
@property(nonatomic) BOOL shareAuthStateAcrossDevices;
350+
343351
/** @property tenantID
344352
@brief The tenant ID of the auth instance. nil if none is available.
345353
*/

FirebaseAuth/Sources/SystemService/FIRAuthStoredUserManager.h

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,35 +62,44 @@ NS_ASSUME_NONNULL_BEGIN
6262
/** @fn getStoredUserForAccessGroup:projectID:error:
6363
@brief The getter of the user stored locally.
6464
@param accessGroup The access group to retrieve the user from.
65+
@param shareAuthStateAcrossDevices If true, the keychain will be synced across the end-user's
66+
iCloud.
6567
@param projectIdentifier An identifier of the project that the user associates with. Currently,
6668
we use API KEY.
6769
@param outError Return value for any error which occurs.
6870
*/
6971
- (nullable FIRUser *)getStoredUserForAccessGroup:(NSString *)accessGroup
72+
shareAuthStateAcrossDevices:(BOOL)shareAuthStateAcrossDevices
7073
projectIdentifier:(NSString *)projectIdentifier
7174
error:(NSError *_Nullable *_Nullable)outError;
7275

7376
/** @fn setStoredUser:forAccessGroup:projectID:error:
7477
@brief The setter of the user stored locally.
7578
@param user The user to be stored.
7679
@param accessGroup The access group to store the user in.
80+
@param shareAuthStateAcrossDevices If true, the keychain will be synced across the end-user's
81+
iCloud.
7782
@param projectIdentifier An identifier of the project that the user associates with. Currently,
7883
we use API KEY.
7984
@param outError Return value for any error which occurs.
8085
*/
8186
- (BOOL)setStoredUser:(FIRUser *)user
82-
forAccessGroup:(NSString *)accessGroup
83-
projectIdentifier:(NSString *)projectIdentifier
84-
error:(NSError *_Nullable *_Nullable)outError;
87+
forAccessGroup:(NSString *)accessGroup
88+
shareAuthStateAcrossDevices:(BOOL)shareAuthStateAcrossDevices
89+
projectIdentifier:(NSString *)projectIdentifier
90+
error:(NSError *_Nullable *_Nullable)outError;
8591

8692
/** @fn removeStoredUserForAccessGroup:projectID:error:
8793
@brief Remove the user that stored locally.
8894
@param accessGroup The access group to remove the user from.
95+
@param shareAuthStateAcrossDevices If true, the keychain will be synced across the end-user's
96+
iCloud.
8997
@param projectIdentifier An identifier of the project that the user associates with. Currently,
9098
we use API KEY.
9199
@param outError Return value for any error which occurs.
92100
*/
93101
- (BOOL)removeStoredUserForAccessGroup:(NSString *)accessGroup
102+
shareAuthStateAcrossDevices:(BOOL)shareAuthStateAcrossDevices
94103
projectIdentifier:(NSString *)projectIdentifier
95104
error:(NSError *_Nullable *_Nullable)outError;
96105

FirebaseAuth/Sources/SystemService/FIRAuthStoredUserManager.m

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ - (BOOL)setStoredUserAccessGroup:(NSString *_Nullable)accessGroup
7272
#pragma mark - User for Access Group
7373

7474
- (FIRUser *)getStoredUserForAccessGroup:(NSString *)accessGroup
75+
shareAuthStateAcrossDevices:(BOOL)shareAuthStateAcrossDevices
7576
projectIdentifier:(NSString *)projectIdentifier
7677
error:(NSError *_Nullable *_Nullable)outError {
7778
NSMutableDictionary *query = [[NSMutableDictionary alloc] init];
@@ -80,6 +81,9 @@ - (FIRUser *)getStoredUserForAccessGroup:(NSString *)accessGroup
8081
query[(__bridge id)kSecAttrAccessGroup] = accessGroup;
8182
query[(__bridge id)kSecAttrService] = projectIdentifier;
8283
query[(__bridge id)kSecAttrAccount] = kSharedKeychainAccountValue;
84+
if (shareAuthStateAcrossDevices) {
85+
query[(__bridge id)kSecAttrSynchronizable] = (__bridge id)kCFBooleanTrue;
86+
}
8387

8488
NSData *data = [self.keychainServices getItemWithQuery:query error:outError];
8589
// If there's an outError parameter and it's populated, or there's no data, return.
@@ -105,17 +109,25 @@ - (FIRUser *)getStoredUserForAccessGroup:(NSString *)accessGroup
105109
}
106110

107111
- (BOOL)setStoredUser:(FIRUser *)user
108-
forAccessGroup:(NSString *)accessGroup
109-
projectIdentifier:(NSString *)projectIdentifier
110-
error:(NSError *_Nullable *_Nullable)outError {
112+
forAccessGroup:(NSString *)accessGroup
113+
shareAuthStateAcrossDevices:(BOOL)shareAuthStateAcrossDevices
114+
projectIdentifier:(NSString *)projectIdentifier
115+
error:(NSError *_Nullable *_Nullable)outError {
111116
NSMutableDictionary *query = [[NSMutableDictionary alloc] init];
112117
query[(__bridge id)kSecClass] = (__bridge id)kSecClassGenericPassword;
113-
query[(__bridge id)kSecAttrAccessible] =
114-
(__bridge id)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly;
118+
if (shareAuthStateAcrossDevices) {
119+
query[(__bridge id)kSecAttrAccessible] = (__bridge id)kSecAttrAccessibleAfterFirstUnlock;
120+
} else {
121+
query[(__bridge id)kSecAttrAccessible] =
122+
(__bridge id)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly;
123+
}
115124

116125
query[(__bridge id)kSecAttrAccessGroup] = accessGroup;
117126
query[(__bridge id)kSecAttrService] = projectIdentifier;
118127
query[(__bridge id)kSecAttrAccount] = kSharedKeychainAccountValue;
128+
if (shareAuthStateAcrossDevices) {
129+
query[(__bridge id)kSecAttrSynchronizable] = (__bridge id)kCFBooleanTrue;
130+
}
119131

120132
#if TARGET_OS_WATCH
121133
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:false];
@@ -138,12 +150,20 @@ - (BOOL)setStoredUser:(FIRUser *)user
138150
}
139151

140152
- (BOOL)removeStoredUserForAccessGroup:(NSString *)accessGroup
153+
shareAuthStateAcrossDevices:(BOOL)shareAuthStateAcrossDevices
141154
projectIdentifier:(NSString *)projectIdentifier
142155
error:(NSError *_Nullable *_Nullable)outError {
143156
NSMutableDictionary *query = [[NSMutableDictionary alloc] init];
144157
query[(__bridge id)kSecClass] = (__bridge id)kSecClassGenericPassword;
145-
query[(__bridge id)kSecAttrAccessible] =
146-
(__bridge id)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly;
158+
if (shareAuthStateAcrossDevices) {
159+
query[(__bridge id)kSecAttrAccessible] = (__bridge id)kSecAttrAccessibleAfterFirstUnlock;
160+
} else {
161+
query[(__bridge id)kSecAttrAccessible] =
162+
(__bridge id)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly;
163+
}
164+
if (shareAuthStateAcrossDevices) {
165+
query[(__bridge id)kSecAttrSynchronizable] = (__bridge id)kCFBooleanTrue;
166+
}
147167

148168
query[(__bridge id)kSecAttrAccessGroup] = accessGroup;
149169
query[(__bridge id)kSecAttrService] = projectIdentifier;

0 commit comments

Comments
 (0)