Skip to content

Commit 405dc51

Browse files
authored
Make tokens in GIDGoogleUser KVO-compliant (#222)
1 parent 89b3ed8 commit 405dc51

File tree

8 files changed

+95
-53
lines changed

8 files changed

+95
-53
lines changed

GoogleSignIn/Sources/GIDGoogleUser.m

Lines changed: 40 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,19 @@
4242

4343
NS_ASSUME_NONNULL_BEGIN
4444

45+
@interface GIDGoogleUser ()
46+
47+
@property(nonatomic, readwrite) GIDToken *accessToken;
48+
49+
@property(nonatomic, readwrite) GIDToken *refreshToken;
50+
51+
@property(nonatomic, readwrite, nullable) GIDToken *idToken;
52+
53+
@end
54+
4555
@implementation GIDGoogleUser {
4656
OIDAuthState *_authState;
4757
GIDConfiguration *_cachedConfiguration;
48-
GIDToken *_cachedAccessToken;
49-
GIDToken *_cachedRefreshToken;
50-
GIDToken *_cachedIdToken;
5158
}
5259

5360
- (nullable NSString *)userID {
@@ -59,7 +66,6 @@ - (nullable NSString *)userID {
5966
return [idTokenDecoded.subject copy];
6067
}
6168
}
62-
6369
return nil;
6470
}
6571

@@ -97,44 +103,9 @@ - (GIDConfiguration *)configuration {
97103
openIDRealm:openIDRealm];
98104
};
99105
}
100-
101106
return _cachedConfiguration;
102107
}
103108

104-
- (GIDToken *)accessToken {
105-
@synchronized(self) {
106-
if (!_cachedAccessToken) {
107-
_cachedAccessToken = [[GIDToken alloc] initWithTokenString:_authState.lastTokenResponse.accessToken
108-
expirationDate:_authState.lastTokenResponse.
109-
accessTokenExpirationDate];
110-
}
111-
}
112-
return _cachedAccessToken;
113-
}
114-
115-
- (GIDToken *)refreshToken {
116-
@synchronized(self) {
117-
if (!_cachedRefreshToken) {
118-
_cachedRefreshToken = [[GIDToken alloc] initWithTokenString:_authState.refreshToken
119-
expirationDate:nil];
120-
}
121-
}
122-
return _cachedRefreshToken;
123-
}
124-
125-
- (nullable GIDToken *)idToken {
126-
@synchronized(self) {
127-
NSString *idTokenString = _authState.lastTokenResponse.idToken;
128-
if (!_cachedIdToken && idTokenString) {
129-
NSDate *idTokenExpirationDate = [[[OIDIDToken alloc]
130-
initWithIDTokenString:idTokenString] expiresAt];
131-
_cachedIdToken = [[GIDToken alloc] initWithTokenString:idTokenString
132-
expirationDate:idTokenExpirationDate];
133-
}
134-
}
135-
return _cachedIdToken;
136-
}
137-
138109
#pragma mark - Private Methods
139110

140111
- (instancetype)initWithAuthState:(OIDAuthState *)authState
@@ -153,10 +124,36 @@ - (void)updateAuthState:(OIDAuthState *)authState
153124
_authentication = [[GIDAuthentication alloc] initWithAuthState:authState];
154125
_profile = profileData;
155126

156-
// These three tokens will be generated in the getter and cached .
157-
_cachedAccessToken = nil;
158-
_cachedRefreshToken = nil;
159-
_cachedIdToken = nil;
127+
[self updateTokensWithAuthState:authState];
128+
}
129+
}
130+
131+
- (void)updateTokensWithAuthState:(OIDAuthState *)authState {
132+
GIDToken *accessToken =
133+
[[GIDToken alloc] initWithTokenString:authState.lastTokenResponse.accessToken
134+
expirationDate:authState.lastTokenResponse.accessTokenExpirationDate];
135+
if (![self.accessToken isEqualToToken:accessToken]) {
136+
self.accessToken = accessToken;
137+
}
138+
139+
GIDToken *refreshToken = [[GIDToken alloc] initWithTokenString:authState.refreshToken
140+
expirationDate:nil];
141+
if (![self.refreshToken isEqualToToken:refreshToken]) {
142+
self.refreshToken = refreshToken;
143+
}
144+
145+
GIDToken *idToken;
146+
NSString *idTokenString = authState.lastTokenResponse.idToken;
147+
if (idTokenString) {
148+
NSDate *idTokenExpirationDate =
149+
[[[OIDIDToken alloc] initWithIDTokenString:idTokenString] expiresAt];
150+
idToken = [[GIDToken alloc] initWithTokenString:idTokenString
151+
expirationDate:idTokenExpirationDate];
152+
} else {
153+
idToken = nil;
154+
}
155+
if ((self.idToken || idToken) && ![self.idToken isEqualToToken:idToken]) {
156+
self.idToken = idToken;
160157
}
161158
}
162159

GoogleSignIn/Tests/Unit/GIDAuthenticationTest.m

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,7 @@ - (GIDAuthentication *)auth {
561561
[OIDTokenResponse testInstanceWithIDToken:idToken
562562
accessToken:kAccessToken
563563
expiresIn:accessTokenExpiresIn
564+
refreshToken:kRefreshToken
564565
tokenRequest:tokenRequest];
565566
return [[GIDAuthentication alloc]
566567
initWithAuthState:[OIDAuthState testInstanceWithTokenResponse:tokenResponse]];
@@ -599,6 +600,7 @@ - (OIDTokenResponse *)tokenResponseWithNewTokens {
599600
return [OIDTokenResponse testInstanceWithIDToken:(_hasIDToken ? [self idTokenNew] : nil)
600601
accessToken:kNewAccessToken
601602
expiresIn:expiresIn
603+
refreshToken:kRefreshToken
602604
tokenRequest:_tokenRequest ?: nil];
603605
}
604606

GoogleSignIn/Tests/Unit/GIDGoogleUserTest.m

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636
#endif
3737

3838
static NSString *const kNewAccessToken = @"new_access_token";
39+
static NSString *const kNewRefreshToken = @"new_refresh_token";
40+
3941
static NSTimeInterval const kTimeAccuracy = 10;
4042
// The difference between times.
4143
// It should be larger than kTimeAccuracy which is used in the method `XCTAssertEqualWithAccuracy`.
@@ -102,19 +104,16 @@ - (void)testUpdateAuthState {
102104
NSTimeInterval accessTokenExpireTime = [[NSDate date] timeIntervalSince1970];
103105
NSTimeInterval idTokenExpireTime = accessTokenExpireTime + kTimeIncrement;
104106

105-
NSString *idToken = [self idTokenWithExpireTime:idTokenExpireTime];
106-
OIDAuthState *authState = [OIDAuthState testInstanceWithIDToken:idToken
107-
accessToken:kAccessToken
108-
accessTokenExpireTime:accessTokenExpireTime];
109-
110-
GIDGoogleUser *user = [[GIDGoogleUser alloc] initWithAuthState:authState profileData:nil];
107+
GIDGoogleUser *user = [self googleUserWithAccessTokenExpireTime:accessTokenExpireTime
108+
idTokenExpireTime:idTokenExpireTime];
111109

112110
NSTimeInterval updatedAccessTokenExpireTime = idTokenExpireTime + kTimeIncrement;
113111
NSTimeInterval updatedIDTokenExpireTime = updatedAccessTokenExpireTime + kTimeIncrement;
114112
NSString *updatedIDToken = [self idTokenWithExpireTime:updatedIDTokenExpireTime];
115113
OIDAuthState *updatedAuthState = [OIDAuthState testInstanceWithIDToken:updatedIDToken
116114
accessToken:kNewAccessToken
117-
accessTokenExpireTime:updatedAccessTokenExpireTime];
115+
accessTokenExpireTime:updatedAccessTokenExpireTime
116+
refreshToken:kNewRefreshToken];
118117
GIDProfileData *updatedProfileData = [GIDProfileData testInstance];
119118

120119
[user updateAuthState:updatedAuthState profileData:updatedProfileData];
@@ -125,11 +124,48 @@ - (void)testUpdateAuthState {
125124
XCTAssertEqualObjects(user.idToken.tokenString, updatedIDToken);
126125
XCTAssertEqualWithAccuracy([user.idToken.expirationDate timeIntervalSince1970],
127126
updatedIDTokenExpireTime, kTimeAccuracy);
127+
XCTAssertEqualObjects(user.refreshToken.tokenString, kNewRefreshToken);
128128
XCTAssertEqual(user.profile, updatedProfileData);
129129
}
130130

131+
// When updating with a new OIDAuthState in which token information is not changed, the token objects
132+
// should remain the same.
133+
- (void)testUpdateAuthState_tokensAreNotChanged {
134+
NSTimeInterval accessTokenExpireTime = [[NSDate date] timeIntervalSince1970];
135+
NSTimeInterval idTokenExpireTime = [[NSDate date] timeIntervalSince1970];
136+
137+
NSString *idToken = [self idTokenWithExpireTime:idTokenExpireTime];
138+
OIDAuthState *authState = [OIDAuthState testInstanceWithIDToken:idToken
139+
accessToken:kAccessToken
140+
accessTokenExpireTime:accessTokenExpireTime
141+
refreshToken:kRefreshToken];
142+
143+
GIDGoogleUser *user = [[GIDGoogleUser alloc] initWithAuthState:authState profileData:nil];
144+
145+
GIDToken *accessTokenBeforeUpdate = user.accessToken;
146+
GIDToken *refreshTokenBeforeUpdate = user.refreshToken;
147+
GIDToken *idTokenBeforeUpdate = user.idToken;
148+
149+
[user updateAuthState:authState profileData:nil];
150+
151+
XCTAssertIdentical(user.accessToken, accessTokenBeforeUpdate);
152+
XCTAssertIdentical(user.idToken, idTokenBeforeUpdate);
153+
XCTAssertIdentical(user.refreshToken, refreshTokenBeforeUpdate);
154+
}
155+
131156
#pragma mark - Helpers
132157

158+
- (GIDGoogleUser *)googleUserWithAccessTokenExpireTime:(NSTimeInterval)accessTokenExpireTime
159+
idTokenExpireTime:(NSTimeInterval)idTokenExpireTime {
160+
NSString *idToken = [self idTokenWithExpireTime:idTokenExpireTime];
161+
OIDAuthState *authState = [OIDAuthState testInstanceWithIDToken:idToken
162+
accessToken:kAccessToken
163+
accessTokenExpireTime:accessTokenExpireTime
164+
refreshToken:kRefreshToken];
165+
166+
return [[GIDGoogleUser alloc] initWithAuthState:authState profileData:nil];
167+
}
168+
133169
// The expireTime should be based on 1970.
134170
- (NSString *)idTokenWithExpireTime:(NSTimeInterval)expireTime {
135171
return [OIDTokenResponse idTokenWithSub:kUserID exp:@(expireTime)];

GoogleSignIn/Tests/Unit/GIDSignInTest.m

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1202,6 +1202,7 @@ - (void)OAuthLoginWithAddScopesFlow:(BOOL)addScopesFlow
12021202
[OIDTokenResponse testInstanceWithIDToken:[OIDTokenResponse fatIDToken]
12031203
accessToken:restoredSignIn ? kAccessToken : nil
12041204
expiresIn:oldAccessToken ? @(300) : nil
1205+
refreshToken:kRefreshToken
12051206
tokenRequest:nil];
12061207

12071208
OIDTokenRequest *tokenRequest = [[OIDTokenRequest alloc]

GoogleSignIn/Tests/Unit/OIDAuthState+Testing.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030

3131
+ (instancetype)testInstanceWithIDToken:(NSString *)idToken
3232
accessToken:(NSString *)accessToken
33-
accessTokenExpireTime:(NSTimeInterval)accessTokenExpireTime;
33+
accessTokenExpireTime:(NSTimeInterval)accessTokenExpireTime
34+
refreshToken:(NSString *)refreshToken;
3435

3536
@end

GoogleSignIn/Tests/Unit/OIDAuthState+Testing.m

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,15 @@ + (instancetype)testInstanceWithTokenResponse:(OIDTokenResponse *)tokenResponse
3535

3636
+ (instancetype)testInstanceWithIDToken:(NSString *)idToken
3737
accessToken:(NSString *)accessToken
38-
accessTokenExpireTime:(NSTimeInterval)accessTokenExpireTime {
38+
accessTokenExpireTime:(NSTimeInterval)accessTokenExpireTime
39+
refreshToken:(NSString *)refreshToken {
3940
NSNumber *accessTokenExpiresIn =
4041
@(accessTokenExpireTime - [[NSDate date] timeIntervalSince1970]);
4142
OIDTokenResponse *newResponse =
4243
[OIDTokenResponse testInstanceWithIDToken:idToken
4344
accessToken:accessToken
4445
expiresIn:accessTokenExpiresIn
46+
refreshToken:refreshToken
4547
tokenRequest:nil];
4648
return [self testInstanceWithTokenResponse:newResponse];
4749
}

GoogleSignIn/Tests/Unit/OIDTokenResponse+Testing.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ extern NSString * const kFatPictureURL;
5656
+ (instancetype)testInstanceWithIDToken:(NSString *)idToken
5757
accessToken:(NSString *)accessToken
5858
expiresIn:(NSNumber *)expiresIn
59+
refreshToken:(NSString *)refreshToken
5960
tokenRequest:(OIDTokenRequest *)tokenRequest;
6061

6162
+ (NSString *)idToken;

GoogleSignIn/Tests/Unit/OIDTokenResponse+Testing.m

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,19 +61,21 @@ + (instancetype)testInstanceWithIDToken:(NSString *)idToken {
6161
return [OIDTokenResponse testInstanceWithIDToken:idToken
6262
accessToken:nil
6363
expiresIn:nil
64+
refreshToken:nil
6465
tokenRequest:nil];
6566
}
6667

6768
+ (instancetype)testInstanceWithIDToken:(NSString *)idToken
6869
accessToken:(NSString *)accessToken
6970
expiresIn:(NSNumber *)expiresIn
71+
refreshToken:(NSString *)refreshToken
7072
tokenRequest:(OIDTokenRequest *)tokenRequest {
7173
NSMutableDictionary<NSString *, NSString *> *parameters;
7274
parameters = [[NSMutableDictionary alloc] initWithDictionary:@{
7375
@"access_token" : accessToken ?: kAccessToken,
7476
@"expires_in" : expiresIn ?: @(kAccessTokenExpiresIn),
7577
@"token_type" : @"example_token_type",
76-
@"refresh_token" : kRefreshToken,
78+
@"refresh_token" : refreshToken ?: kRefreshToken,
7779
@"scope" : [OIDScopeUtilities scopesWithArray:@[ OIDAuthorizationRequestTestingScope2 ]],
7880
@"server_code" : kServerAuthCode,
7981
}];

0 commit comments

Comments
 (0)