Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[VwG] Add "Refresh" button to sample app to refresh tokens. #453

Merged
merged 6 commits into from
Jul 17, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,8 @@

@implementation GIDVerifiedAccountDetailHandlingFake

- (instancetype)initWithLastTokenResponse:(OIDTokenResponse *)tokenResponse
accountDetails:(NSArray<GIDVerifiableAccountDetail *> *)accountDetails
authState:(OIDAuthState *)authState {
- (instancetype)initWithAccountDetails:(NSArray<GIDVerifiableAccountDetail *> *)accountDetails
authState:(OIDAuthState *)authState {
self = [super init];
if (self) {
NSAssert(false, @"This class is only to be used in testing. Do not use.");
Expand Down Expand Up @@ -64,9 +63,8 @@ - (void)refreshTokensWithCompletion:(nullable void (^)(GIDVerifiedAccountDetailR
[self updateVerifiedDetailsWithTokenResponse:_tokenResponse];

GIDVerifiedAccountDetailResult *result =
[[GIDVerifiedAccountDetailResult alloc] initWithLastTokenResponse:_tokenResponse
accountDetails:_verifiedAccountDetails
authState:_verifiedAuthState];
[[GIDVerifiedAccountDetailResult alloc] initWithAccountDetails:_verifiedAccountDetails
authState:_verifiedAuthState];
completion(result, _error);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,10 @@

@implementation GIDVerifiedAccountDetailResult

- (instancetype)initWithLastTokenResponse:(OIDTokenResponse *)tokenResponse
accountDetails:(NSArray<GIDVerifiableAccountDetail *> *)accountDetails
authState:(OIDAuthState *)authState {
- (instancetype)initWithAccountDetails:(NSArray<GIDVerifiableAccountDetail *> *)accountDetails
authState:(OIDAuthState *)authState {
self = [super init];
if (self) {
_expirationDate = tokenResponse.accessTokenExpirationDate;
_accessTokenString = tokenResponse.accessToken;
_refreshTokenString = tokenResponse.refreshToken;
_verifiedAccountDetails = accountDetails;
_verifiedAuthState = authState;
}
Expand All @@ -53,23 +49,12 @@ - (instancetype)initWithLastTokenResponse:(OIDTokenResponse *)tokenResponse
// TODO: Migrate refresh logic to `GIDGoogleuser` (#441).
- (void)refreshTokensWithCompletion:(nullable void (^)(GIDVerifiedAccountDetailResult *,
NSError *))completion {
OIDAuthorizationResponse *authResponse = self.verifiedAuthState.lastAuthorizationResponse;
OIDAuthorizationRequest *request = authResponse.request;

OIDTokenRequest *refreshRequest =
[[OIDTokenRequest alloc] initWithConfiguration:request.configuration
grantType:OIDGrantTypeAuthorizationCode
authorizationCode:authResponse.authorizationCode
redirectURL:request.redirectURL
clientID:request.clientID
clientSecret:request.clientSecret
scope:request.scope
refreshToken:self.refreshTokenString
codeVerifier:request.codeVerifier
additionalParameters:request.additionalParameters];
NSDictionary<NSString *, NSString *> *additionalParameters =
self.verifiedAuthState.lastAuthorizationResponse.request.additionalParameters;
OIDTokenRequest *refreshRequest =
[self.verifiedAuthState tokenRefreshRequestWithAdditionalHeaders:additionalParameters];

[OIDAuthorizationService performTokenRequest:refreshRequest
originalAuthorizationResponse:authResponse
callback:^(OIDTokenResponse * _Nullable tokenResponse,
NSError * _Nullable error) {
if (tokenResponse) {
Expand All @@ -84,10 +69,6 @@ - (void)refreshTokensWithCompletion:(nullable void (^)(GIDVerifiedAccountDetailR

- (void)updateVerifiedDetailsWithTokenResponse:(nullable OIDTokenResponse *)tokenResponse {
if (tokenResponse) {
_expirationDate = tokenResponse.accessTokenExpirationDate;
_accessTokenString = tokenResponse.accessToken;
_refreshTokenString = tokenResponse.refreshToken;

NSArray<NSString *> *accountDetailsString =
[OIDScopeUtilities scopesArrayWithString:tokenResponse.scope];
NSMutableArray<GIDVerifiableAccountDetail *> *verifiedAccountDetails = [NSMutableArray array];
Expand All @@ -104,6 +85,18 @@ - (void)updateVerifiedDetailsWithTokenResponse:(nullable OIDTokenResponse *)toke
}
}

- (nullable NSString *)accessTokenString {
return self.verifiedAuthState.lastTokenResponse.accessToken;
}

- (nullable NSString *)refreshTokenString {
return self.verifiedAuthState.refreshToken;
}

- (nullable NSDate *)expirationDate {
return self.verifiedAuthState.lastTokenResponse.accessTokenExpirationDate;
}

- (BOOL)isEqual:(id)object {
if (![object isKindOfClass:[GIDVerifiedAccountDetailResult class]]) {
return NO;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -271,9 +271,8 @@ - (void)addCompletionCallback:(GIDAuthFlow *)authFlow {
} else {
OIDAuthState *authState = handlerAuthFlow.authState;
GIDVerifiedAccountDetailResult *verifiedResult = [[GIDVerifiedAccountDetailResult alloc]
initWithLastTokenResponse:authState.lastTokenResponse
accountDetails:self->_accountDetails
authState:authState];
initWithAccountDetails:self->_accountDetails
authState:authState];
completion(verifiedResult, nil);
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,12 @@ NS_ASSUME_NONNULL_BEGIN

/// Initialize a `GIDVerifiedAccountDetailHandling` object by specifying all available properties.
///
/// @param tokenResponse The last token response with expiration date, access token, and refresh token.
/// @param accountDetails A list of verified account details.
/// @param authState An updated to update the token response or authorization error.
///
/// @return An initialized `GIDVerifiedAccountDetailHandling` instance with expiration date, access token, and refresh token.
- (instancetype)initWithLastTokenResponse:(OIDTokenResponse *)tokenResponse
accountDetails:(NSArray<GIDVerifiableAccountDetail *> *)accountDetails
authState:(OIDAuthState *)authState;
- (instancetype)initWithAccountDetails:(NSArray<GIDVerifiableAccountDetail *> *)accountDetails
authState:(OIDAuthState *)authState;

/// Refresh the access token and refresh token with the current authorization state.
///
Expand Down
12 changes: 5 additions & 7 deletions GoogleSignIn/Tests/Unit/GIDVerifiedAccountDetailResultTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,8 @@ - (void)testInit {
@[verifiedAccountDetail, verifiedAccountDetail];

GIDVerifiedAccountDetailResult *result =
[[GIDVerifiedAccountDetailResult alloc] initWithLastTokenResponse:authState.lastTokenResponse
accountDetails:verifiedList
authState:authState];
[[GIDVerifiedAccountDetailResult alloc] initWithAccountDetails:verifiedList
authState:authState];

XCTAssertEqual(result.verifiedAuthState, authState);
XCTAssertEqual(result.verifiedAccountDetails, verifiedList);
Expand All @@ -68,9 +67,8 @@ - (void)testRefreshTokensWithCompletion_success {
NSArray<GIDVerifiableAccountDetail *> *expectedVerifiedList =
@[verifiedAccountDetail];
GIDVerifiedAccountDetailResult *expectedResult =
[[GIDVerifiedAccountDetailResult alloc] initWithLastTokenResponse:authState.lastTokenResponse
accountDetails:expectedVerifiedList
authState:authState];
[[GIDVerifiedAccountDetailResult alloc] initWithAccountDetails:expectedVerifiedList
authState:authState];

XCTestExpectation *expectation =
[self expectationWithDescription:@"Refreshed verified account details completion called"];
Expand All @@ -97,7 +95,7 @@ - (void)testRefreshTokensWithCompletion_noTokenResponse {
error:expectedError];

XCTestExpectation *expectation =
[self expectationWithDescription:@"Refreshed verified account details completion called"];
[self expectationWithDescription:@"Refreshed verified account details completion called"];
[result refreshTokensWithCompletion:^(GIDVerifiedAccountDetailResult * _Nullable refreshedResult,
NSError * _Nullable error) {
XCTAssertNotNil(error);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
archiveVersion = 1;
classes = {
};
objectVersion = 51;
objectVersion = 54;
objects = {

/* Begin PBXBuildFile section */
4C6A2BA2321434ACBD2AF201 /* Pods_DaysUntilBirthdayForPod__macOS_.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 926A15D393D684C68E09FB0F /* Pods_DaysUntilBirthdayForPod__macOS_.framework */; };
641495072C3C90E100C9A613 /* VerificationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 641495062C3C90E100C9A613 /* VerificationView.swift */; };
641495082C3C90E100C9A613 /* VerificationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 641495062C3C90E100C9A613 /* VerificationView.swift */; };
7345AD032703D9470020AFB1 /* DaysUntilBirthday.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7345AD022703D9470020AFB1 /* DaysUntilBirthday.swift */; };
7345AD052703D9470020AFB1 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7345AD042703D9470020AFB1 /* ContentView.swift */; };
7345AD072703D9480020AFB1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7345AD062703D9480020AFB1 /* Assets.xcassets */; };
Expand Down Expand Up @@ -45,6 +47,7 @@
1A129363EBB5DF1F41FAAB14 /* Pods-DaysUntilBirthdayForPod(macOS).release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DaysUntilBirthdayForPod(macOS).release.xcconfig"; path = "Target Support Files/Pods-DaysUntilBirthdayForPod(macOS)/Pods-DaysUntilBirthdayForPod(macOS).release.xcconfig"; sourceTree = "<group>"; };
29BEB027A694593FA0450863 /* Pods-DaysUntilBirthdayForPod(iOS).debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DaysUntilBirthdayForPod(iOS).debug.xcconfig"; path = "Target Support Files/Pods-DaysUntilBirthdayForPod(iOS)/Pods-DaysUntilBirthdayForPod(iOS).debug.xcconfig"; sourceTree = "<group>"; };
5CF615341A61D92D89389D44 /* Pods-DaysUntilBirthdayForPod (macOS).release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DaysUntilBirthdayForPod (macOS).release.xcconfig"; path = "Target Support Files/Pods-DaysUntilBirthdayForPod (macOS)/Pods-DaysUntilBirthdayForPod (macOS).release.xcconfig"; sourceTree = "<group>"; };
641495062C3C90E100C9A613 /* VerificationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VerificationView.swift; sourceTree = "<group>"; };
7345ACFF2703D9470020AFB1 /* DaysUntilBirthdayForPod (iOS).app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "DaysUntilBirthdayForPod (iOS).app"; sourceTree = BUILT_PRODUCTS_DIR; };
7345AD022703D9470020AFB1 /* DaysUntilBirthday.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DaysUntilBirthday.swift; sourceTree = "<group>"; };
7345AD042703D9470020AFB1 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -195,6 +198,7 @@
children = (
7345AD042703D9470020AFB1 /* ContentView.swift */,
739FCC45270E467600C92042 /* BirthdayView.swift */,
641495062C3C90E100C9A613 /* VerificationView.swift */,
7345AD112703D9C30020AFB1 /* SignInView.swift */,
7345AD142703D9C30020AFB1 /* UserProfileImageView.swift */,
);
Expand Down Expand Up @@ -413,6 +417,7 @@
buildActionMask = 2147483647;
files = (
739FCC48270E659A00C92042 /* Birthday.swift in Sources */,
641495072C3C90E100C9A613 /* VerificationView.swift in Sources */,
739FCC46270E467600C92042 /* BirthdayView.swift in Sources */,
7345AD1B2703D9C30020AFB1 /* SignInView.swift in Sources */,
7345AD212703D9C30020AFB1 /* GoogleSignInAuthenticator.swift in Sources */,
Expand All @@ -432,6 +437,7 @@
buildActionMask = 2147483647;
files = (
73DB41912805FBFD0028B8D3 /* SignInView.swift in Sources */,
641495082C3C90E100C9A613 /* VerificationView.swift in Sources */,
73DB418B2805FBC40028B8D3 /* BirthdayLoader.swift in Sources */,
73DB418D2805FBD00028B8D3 /* AuthenticationViewModel.swift in Sources */,
73DB418F2805FBF50028B8D3 /* ContentView.swift in Sources */,
Expand Down Expand Up @@ -577,14 +583,15 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_ASSET_PATHS = "\"iOS/Preview Content\"";
DEVELOPMENT_TEAM = JA85M8JD4Z;
ENABLE_PREVIEWS = YES;
INFOPLIST_FILE = iOS/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.google.DaysUntilBirthday;
PRODUCT_BUNDLE_IDENTIFIER = "testing-com.google.DaysUntilBirthday";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
Expand All @@ -599,14 +606,15 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_ASSET_PATHS = "\"iOS/Preview Content\"";
DEVELOPMENT_TEAM = JA85M8JD4Z;
ENABLE_PREVIEWS = YES;
INFOPLIST_FILE = iOS/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.google.DaysUntilBirthday;
PRODUCT_BUNDLE_IDENTIFIER = "testing-com.google.DaysUntilBirthday";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,32 @@ final class GoogleSignInAuthenticator: ObservableObject {
self.authViewModel = authViewModel
}

#if os(iOS)
/// Verifies the user's age based upon the selected account.
/// - note: Successful calls to this will set the `authViewModel`'s `verificationState` property.
func verifyAccountDetails() {
let accountDetails: [GIDVerifiableAccountDetail] = [
GIDVerifiableAccountDetail(accountDetailType:.ageOver18)
]

guard let rootViewController = UIApplication.shared.windows.first?.rootViewController else {
print("There is no root view controller!")
return
}

let verifyAccountDetail = GIDVerifyAccountDetail()
verifyAccountDetail.verifyAccountDetails(accountDetails, presenting: rootViewController) {
verifyResult, error in
guard let verifyResult = verifyResult else {
self.authViewModel.verificationState = .unverified
print("Error! \(String(describing: error))")
return
}
self.authViewModel.verificationState = .verified(verifyResult)
}
}
#endif

/// Signs in the user based upon the selected account.'
/// - note: Successful calls to this will set the `authViewModel`'s `state` property.
func signIn() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ final class AuthenticationViewModel: ObservableObject {
/// The user's log in status.
/// - note: This will publish updates when its value changes.
@Published var state: State

#if os(iOS)
/// The user's account verification status.
/// - note: This will publish updates when its value changes.
@Published var verificationState: VerificationState
#endif

private var authenticator: GoogleSignInAuthenticator {
return GoogleSignInAuthenticator(authViewModel: self)
}
Expand All @@ -43,6 +50,9 @@ final class AuthenticationViewModel: ObservableObject {
} else {
self.state = .signedOut
}
#if os(iOS)
self.verificationState = .unverified
#endif
}

/// Signs the user in.
Expand All @@ -60,6 +70,18 @@ final class AuthenticationViewModel: ObservableObject {
authenticator.disconnect()
}

#if os(iOS)
/// Verifies the user.
func verifyAccountDetails() {
switch self.verificationState {
case .unverified:
authenticator.verifyAccountDetails()
case .verified:
return
}
}
#endif

var hasBirthdayReadScope: Bool {
return authorizedScopes.contains(BirthdayLoader.birthdayReadScope)
}
Expand All @@ -80,4 +102,14 @@ extension AuthenticationViewModel {
/// The user is logged out.
case signedOut
}

#if os(iOS)
/// An enumeration representing verified status.
enum VerificationState {
/// The user's account is verified and is the associated value of this case.
case verified(GIDVerifiedAccountDetailResult)
/// The user's account is not verified.
case unverified
}
#endif
}
Loading
Loading