From b34f5a924a53fa559a381ae73a8da6f8a789d9eb Mon Sep 17 00:00:00 2001 From: Vojtech Novak Date: Fri, 13 Sep 2024 03:01:23 +0200 Subject: [PATCH] feat: allow providing custom nonce (#402) --- GoogleSignIn/Sources/GIDSignIn.m | 34 ++++++++++-- .../Sources/GIDSignInInternalOptions.h | 6 +++ .../Sources/GIDSignInInternalOptions.m | 4 ++ .../Sources/Public/GoogleSignIn/GIDSignIn.h | 49 ++++++++++++++++- GoogleSignIn/Tests/Unit/GIDSignInTest.m | 54 ++++++++++++++++--- .../Unit/OIDAuthorizationRequest+Testing.h | 12 +++-- .../Unit/OIDAuthorizationRequest+Testing.m | 5 ++ .../Unit/OIDAuthorizationResponse+Testing.h | 1 + .../Unit/OIDAuthorizationResponse+Testing.m | 5 +- .../Tests/Unit/OIDTokenResponse+Testing.m | 3 +- Samples/ObjC/SignInSample/Podfile | 2 +- Samples/ObjC/SignInSample/README.md | 2 +- .../Source/SignInViewController.m | 5 ++ 13 files changed, 158 insertions(+), 24 deletions(-) diff --git a/GoogleSignIn/Sources/GIDSignIn.m b/GoogleSignIn/Sources/GIDSignIn.m index 0f16caa2..de7b6681 100644 --- a/GoogleSignIn/Sources/GIDSignIn.m +++ b/GoogleSignIn/Sources/GIDSignIn.m @@ -272,12 +272,25 @@ - (void)signInWithPresentingViewController:(UIViewController *)presentingViewCon hint:(nullable NSString *)hint additionalScopes:(nullable NSArray *)additionalScopes completion:(nullable GIDSignInCompletion)completion { + [self signInWithPresentingViewController:presentingViewController + hint:hint + additionalScopes:additionalScopes + nonce:nil + completion:completion]; +} + +- (void)signInWithPresentingViewController:(UIViewController *)presentingViewController + hint:(nullable NSString *)hint + additionalScopes:(nullable NSArray *)additionalScopes + nonce:(nullable NSString *)nonce + completion:(nullable GIDSignInCompletion)completion { GIDSignInInternalOptions *options = [GIDSignInInternalOptions defaultOptionsWithConfiguration:_configuration presentingViewController:presentingViewController loginHint:hint addScopesFlow:NO scopes:additionalScopes + nonce:nonce completion:completion]; [self signInWithOptions:options]; } @@ -350,12 +363,25 @@ - (void)signInWithPresentingWindow:(NSWindow *)presentingWindow hint:(nullable NSString *)hint additionalScopes:(nullable NSArray *)additionalScopes completion:(nullable GIDSignInCompletion)completion { + [self signInWithPresentingWindow:presentingWindow + hint:hint + additionalScopes:additionalScopes + nonce:nil + completion:completion]; +} + +- (void)signInWithPresentingWindow:(NSWindow *)presentingWindow + hint:(nullable NSString *)hint + additionalScopes:(nullable NSArray *)additionalScopes + nonce:(nullable NSString *)nonce + completion:(nullable GIDSignInCompletion)completion { GIDSignInInternalOptions *options = [GIDSignInInternalOptions defaultOptionsWithConfiguration:_configuration presentingWindow:presentingWindow loginHint:hint addScopesFlow:NO scopes:additionalScopes + nonce:nonce completion:completion]; [self signInWithOptions:options]; } @@ -573,7 +599,7 @@ - (void)signInWithOptions:(GIDSignInInternalOptions *)options { if (!_configuration) { // NOLINTNEXTLINE(google-objc-avoid-throwing-exception) [NSException raise:NSInvalidArgumentException - format:@"No active configuration. Make sure GIDClientID is set in Info.plist."]; + format:@"No active configuration. Make sure GIDClientID is set in Info.plist."]; return; } @@ -667,7 +693,6 @@ - (void)authorizationRequestWithOptions:(GIDSignInInternalOptions *)options comp [_timedLoader startTiming]; [self->_appCheck getLimitedUseTokenWithCompletion:^(GACAppCheckToken * _Nullable token, NSError * _Nullable error) { - OIDAuthorizationRequest *request = nil; if (token) { additionalParameters[kClientAssertionTypeParameter] = kClientAssertionTypeParameterValue; additionalParameters[kClientAssertionParameter] = token.token; @@ -677,7 +702,7 @@ - (void)authorizationRequestWithOptions:(GIDSignInInternalOptions *)options comp NSLog(@"[Google Sign-In iOS]: Error retrieving App Check limited use token: %@", error); } #endif - request = [self authorizationRequestWithOptions:options + OIDAuthorizationRequest *request = [self authorizationRequestWithOptions:options additionalParameters:additionalParameters]; if (self->_timedLoader.animationStatus == GIDTimedLoaderAnimationStatusAnimating) { [self->_timedLoader stopTimingWithCompletion:^{ @@ -707,6 +732,7 @@ - (void)authorizationRequestWithOptions:(GIDSignInInternalOptions *)options comp scopes:options.scopes redirectURL:[self redirectURLWithOptions:options] responseType:OIDResponseTypeCode + nonce:options.nonce additionalParameters:additionalParameters]; return request; } @@ -758,7 +784,7 @@ - (NSURL *)redirectURLWithOptions:(GIDSignInInternalOptions *)options { - (void)processAuthorizationResponse:(OIDAuthorizationResponse *)authorizationResponse error:(NSError *)error - emmSupport:(NSString *)emmSupport{ + emmSupport:(NSString *)emmSupport { if (_restarting) { // The auth flow is restarting, so the work here would be performed in the next round. _restarting = NO; diff --git a/GoogleSignIn/Sources/GIDSignInInternalOptions.h b/GoogleSignIn/Sources/GIDSignInInternalOptions.h index f1aff409..1ea78f46 100644 --- a/GoogleSignIn/Sources/GIDSignInInternalOptions.h +++ b/GoogleSignIn/Sources/GIDSignInInternalOptions.h @@ -64,6 +64,10 @@ NS_ASSUME_NONNULL_BEGIN /// The login hint to be used during the flow. @property(nonatomic, copy, nullable) NSString *loginHint; +/// A cryptographically random value used to associate a Client session with an ID Token, +/// and to mitigate replay attacks. +@property(nonatomic, readonly, copy, nullable) NSString *nonce; + /// Creates the default options. #if TARGET_OS_IOS || TARGET_OS_MACCATALYST + (instancetype)defaultOptionsWithConfiguration:(nullable GIDConfiguration *)configuration @@ -77,6 +81,7 @@ NS_ASSUME_NONNULL_BEGIN loginHint:(nullable NSString *)loginHint addScopesFlow:(BOOL)addScopesFlow scopes:(nullable NSArray *)scopes + nonce:(nullable NSString *)nonce completion:(nullable GIDSignInCompletion)completion; #elif TARGET_OS_OSX @@ -91,6 +96,7 @@ NS_ASSUME_NONNULL_BEGIN loginHint:(nullable NSString *)loginHint addScopesFlow:(BOOL)addScopesFlow scopes:(nullable NSArray *)scopes + nonce:(nullable NSString *)nonce completion:(nullable GIDSignInCompletion)completion; #endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST diff --git a/GoogleSignIn/Sources/GIDSignInInternalOptions.m b/GoogleSignIn/Sources/GIDSignInInternalOptions.m index bfb21643..523bd48d 100644 --- a/GoogleSignIn/Sources/GIDSignInInternalOptions.m +++ b/GoogleSignIn/Sources/GIDSignInInternalOptions.m @@ -31,6 +31,7 @@ + (instancetype)defaultOptionsWithConfiguration:(nullable GIDConfiguration *)con loginHint:(nullable NSString *)loginHint addScopesFlow:(BOOL)addScopesFlow scopes:(nullable NSArray *)scopes + nonce:(nullable NSString *)nonce completion:(nullable GIDSignInCompletion)completion { #elif TARGET_OS_OSX + (instancetype)defaultOptionsWithConfiguration:(nullable GIDConfiguration *)configuration @@ -38,6 +39,7 @@ + (instancetype)defaultOptionsWithConfiguration:(nullable GIDConfiguration *)con loginHint:(nullable NSString *)loginHint addScopesFlow:(BOOL)addScopesFlow scopes:(nullable NSArray *)scopes + nonce:(nullable NSString *)nonce completion:(nullable GIDSignInCompletion)completion { #endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST GIDSignInInternalOptions *options = [[GIDSignInInternalOptions alloc] init]; @@ -54,6 +56,7 @@ + (instancetype)defaultOptionsWithConfiguration:(nullable GIDConfiguration *)con options->_loginHint = loginHint; options->_completion = completion; options->_scopes = [GIDScopes scopesWithBasicProfile:scopes]; + options->_nonce = nonce; } return options; } @@ -80,6 +83,7 @@ + (instancetype)defaultOptionsWithConfiguration:(nullable GIDConfiguration *)con loginHint:loginHint addScopesFlow:addScopesFlow scopes:@[] + nonce:nil completion:completion]; return options; } diff --git a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h index 2cdcbe24..1025a92a 100644 --- a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h +++ b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h @@ -196,6 +196,31 @@ NS_EXTENSION_UNAVAILABLE("The sign-in flow is not supported in App Extensions.") NSError *_Nullable error))completion NS_EXTENSION_UNAVAILABLE("The sign-in flow is not supported in App Extensions."); + +/// Starts an interactive sign-in flow on iOS using the provided hint, additional scopes, and nonce. +/// +/// The completion will be called at the end of this process. Any saved sign-in state will be +/// replaced by the result of this flow. Note that this method should not be called when the app is +/// starting up, (e.g in `application:didFinishLaunchingWithOptions:`); instead use the +/// `restorePreviousSignInWithCompletion:` method to restore a previous sign-in. +/// +/// @param presentingViewController The view controller used to present `SFSafariViewController` on +/// iOS 9 and 10. +/// @param hint An optional hint for the authorization server, for example the user's ID or email +/// address, to be prefilled if possible. +/// @param additionalScopes An optional array of scopes to request in addition to the basic profile scopes. +/// @param nonce A custom nonce. +/// @param completion The optional block that is called on completion. This block will +/// be called asynchronously on the main queue. +- (void)signInWithPresentingViewController:(UIViewController *)presentingViewController + hint:(nullable NSString *)hint + additionalScopes:(nullable NSArray *)additionalScopes + nonce:(nullable NSString *)nonce + completion: + (nullable void (^)(GIDSignInResult *_Nullable signInResult, + NSError *_Nullable error))completion + NS_EXTENSION_UNAVAILABLE("The sign-in flow is not supported in App Extensions."); + #elif TARGET_OS_OSX /// Starts an interactive sign-in flow on macOS. @@ -229,7 +254,7 @@ NS_EXTENSION_UNAVAILABLE("The sign-in flow is not supported in App Extensions.") completion:(nullable void (^)(GIDSignInResult *_Nullable signInResult, NSError *_Nullable error))completion; -/// Starts an interactive sign-in flow on macOS using the provided hint. +/// Starts an interactive sign-in flow on macOS using the provided hint and additional scopes. /// /// The completion will be called at the end of this process. Any saved sign-in state will be /// replaced by the result of this flow. Note that this method should not be called when the app is @@ -248,6 +273,28 @@ NS_EXTENSION_UNAVAILABLE("The sign-in flow is not supported in App Extensions.") completion:(nullable void (^)(GIDSignInResult *_Nullable signInResult, NSError *_Nullable error))completion; +/// Starts an interactive sign-in flow on macOS using the provided hint, additional scopes, and nonce. +/// +/// The completion will be called at the end of this process. Any saved sign-in state will be +/// replaced by the result of this flow. Note that this method should not be called when the app is +/// starting up, (e.g in `application:didFinishLaunchingWithOptions:`); instead use the +/// `restorePreviousSignInWithCompletion:` method to restore a previous sign-in. +/// +/// @param presentingWindow The window used to supply `presentationContextProvider` for `ASWebAuthenticationSession`. +/// @param hint An optional hint for the authorization server, for example the user's ID or email +/// address, to be prefilled if possible. +/// @param additionalScopes An optional array of scopes to request in addition to the basic profile scopes. +/// @param nonce A custom nonce. +/// @param completion The optional block that is called on completion. This block will +/// be called asynchronously on the main queue. +- (void)signInWithPresentingWindow:(NSWindow *)presentingWindow + hint:(nullable NSString *)hint + additionalScopes:(nullable NSArray *)additionalScopes + nonce:(nullable NSString *)nonce + completion:(nullable void (^)(GIDSignInResult *_Nullable signInResult, + NSError *_Nullable error))completion; + + #endif @end diff --git a/GoogleSignIn/Tests/Unit/GIDSignInTest.m b/GoogleSignIn/Tests/Unit/GIDSignInTest.m index 0f35dc6b..6bdd19d1 100644 --- a/GoogleSignIn/Tests/Unit/GIDSignInTest.m +++ b/GoogleSignIn/Tests/Unit/GIDSignInTest.m @@ -500,8 +500,7 @@ - (void)testRestorePreviousSignInNoRefresh_hasPreviousUser { // Mock generating a GIDConfiguration when initializing GIDGoogleUser. OIDAuthorizationResponse *authResponse = - [OIDAuthorizationResponse testInstanceWithAdditionalParameters:nil - errorString:nil]; + [OIDAuthorizationResponse testInstance]; OCMStub([_authState lastAuthorizationResponse]).andReturn(authResponse); OCMStub([_tokenResponse idToken]).andReturn(kFakeIDToken); @@ -676,7 +675,8 @@ - (void)testOAuthLogin_AdditionalScopes { oldAccessToken:NO modalCancel:NO useAdditionalScopes:YES - additionalScopes:nil]; + additionalScopes:nil + manualNonce:nil]; expectedScopeString = [@[ @"email", @"profile" ] componentsJoinedByString:@" "]; XCTAssertEqualObjects(_savedAuthorizationRequest.scope, expectedScopeString); @@ -690,7 +690,8 @@ - (void)testOAuthLogin_AdditionalScopes { oldAccessToken:NO modalCancel:NO useAdditionalScopes:YES - additionalScopes:@[ kScope ]]; + additionalScopes:@[ kScope ] + manualNonce:nil]; expectedScopeString = [@[ kScope, @"email", @"profile" ] componentsJoinedByString:@" "]; XCTAssertEqualObjects(_savedAuthorizationRequest.scope, expectedScopeString); @@ -704,7 +705,8 @@ - (void)testOAuthLogin_AdditionalScopes { oldAccessToken:NO modalCancel:NO useAdditionalScopes:YES - additionalScopes:@[ kScope, kScope2 ]]; + additionalScopes:@[ kScope, kScope2 ] + manualNonce:nil]; expectedScopeString = [@[ kScope, kScope2, @"email", @"profile" ] componentsJoinedByString:@" "]; XCTAssertEqualObjects(_savedAuthorizationRequest.scope, expectedScopeString); @@ -796,6 +798,37 @@ - (void)testOpenIDRealm { XCTAssertEqual(params[kOpenIDRealmKey], kOpenIDRealm, @"OpenID Realm should match."); } +- (void)testManualNonce { + _signIn.configuration = [[GIDConfiguration alloc] initWithClientID:kClientId + serverClientID:nil + hostedDomain:nil + openIDRealm:kOpenIDRealm]; + + OCMStub( + [_keychainStore saveAuthSession:OCMOCK_ANY error:OCMArg.anyObjectRef] + ).andDo(^(NSInvocation *invocation) { + self->_keychainSaved = self->_saveAuthorizationReturnValue; + }); + + NSString* manualNonce = @"manual_nonce"; + + [self OAuthLoginWithAddScopesFlow:NO + authError:nil + tokenError:nil + emmPasscodeInfoRequired:NO + keychainError:NO + restoredSignIn:NO + oldAccessToken:NO + modalCancel:NO + useAdditionalScopes:NO + additionalScopes:@[] + manualNonce:manualNonce]; + + XCTAssertEqualObjects(_savedAuthorizationRequest.nonce, + manualNonce, + @"Provided nonce should match nonce in authorization request."); +} + - (void)testOAuthLogin_LoginHint { _hint = kUserEmail; @@ -1375,7 +1408,8 @@ - (void)OAuthLoginWithAddScopesFlow:(BOOL)addScopesFlow oldAccessToken:oldAccessToken modalCancel:modalCancel useAdditionalScopes:NO - additionalScopes:nil]; + additionalScopes:nil + manualNonce:nil]; } // The authorization flow with parameters to control which branches to take. @@ -1388,11 +1422,12 @@ - (void)OAuthLoginWithAddScopesFlow:(BOOL)addScopesFlow oldAccessToken:(BOOL)oldAccessToken modalCancel:(BOOL)modalCancel useAdditionalScopes:(BOOL)useAdditionalScopes - additionalScopes:(NSArray *)additionalScopes { + additionalScopes:(NSArray *)additionalScopes + manualNonce:(NSString *)nonce { if (restoredSignIn) { // clearAndAuthenticateWithOptions [[[_authorization expect] andReturn:_authState] authState]; - BOOL isAuthorized = restoredSignIn ? YES : NO; + BOOL isAuthorized = restoredSignIn; [[[_authState expect] andReturnValue:[NSNumber numberWithBool:isAuthorized]] isAuthorized]; } @@ -1400,6 +1435,7 @@ - (void)OAuthLoginWithAddScopesFlow:(BOOL)addScopesFlow @{ @"emm_passcode_info_required" : @"1" } : nil; OIDAuthorizationResponse *authResponse = [OIDAuthorizationResponse testInstanceWithAdditionalParameters:additionalParameters + nonce:nonce errorString:authError]; OIDTokenResponse *tokenResponse = @@ -1475,6 +1511,8 @@ - (void)OAuthLoginWithAddScopesFlow:(BOOL)addScopesFlow [_signIn signInWithPresentingWindow:_presentingWindow #endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST hint:_hint + additionalScopes:nil + nonce:nonce completion:completion]; } } diff --git a/GoogleSignIn/Tests/Unit/OIDAuthorizationRequest+Testing.h b/GoogleSignIn/Tests/Unit/OIDAuthorizationRequest+Testing.h index 310b45b7..a70d5e80 100644 --- a/GoogleSignIn/Tests/Unit/OIDAuthorizationRequest+Testing.h +++ b/GoogleSignIn/Tests/Unit/OIDAuthorizationRequest+Testing.h @@ -20,13 +20,15 @@ #import #endif -extern NSString *const OIDAuthorizationRequestTestingClientID; -extern NSString *const OIDAuthorizationRequestTestingScope; -extern NSString *const OIDAuthorizationRequestTestingScope2; -extern NSString *const OIDAuthorizationRequestTestingCodeVerifier; +extern NSString * _Nonnull const OIDAuthorizationRequestTestingClientID; +extern NSString * _Nonnull const OIDAuthorizationRequestTestingScope; +extern NSString * _Nonnull const OIDAuthorizationRequestTestingScope2; +extern NSString * _Nonnull const OIDAuthorizationRequestTestingCodeVerifier; @interface OIDAuthorizationRequest (Testing) -+ (instancetype)testInstance; ++ (instancetype _Nonnull)testInstance; + ++ (instancetype _Nonnull)testInstanceWithNonce:(nullable NSString *)nonce; @end diff --git a/GoogleSignIn/Tests/Unit/OIDAuthorizationRequest+Testing.m b/GoogleSignIn/Tests/Unit/OIDAuthorizationRequest+Testing.m index 29e9013f..a8dd0b81 100644 --- a/GoogleSignIn/Tests/Unit/OIDAuthorizationRequest+Testing.m +++ b/GoogleSignIn/Tests/Unit/OIDAuthorizationRequest+Testing.m @@ -32,6 +32,10 @@ @implementation OIDAuthorizationRequest (Testing) + (instancetype)testInstance { + return [self testInstanceWithNonce:nil]; +} + ++ (instancetype)testInstanceWithNonce:(nullable NSString *)nonce { return [[OIDAuthorizationRequest alloc] initWithConfiguration:[OIDServiceConfiguration testInstance] clientId:OIDAuthorizationRequestTestingClientID @@ -39,6 +43,7 @@ + (instancetype)testInstance { OIDAuthorizationRequestTestingScope2 ] redirectURL:[NSURL URLWithString:@"http://test.com"] responseType:OIDResponseTypeCode + nonce:nonce additionalParameters:nil]; } diff --git a/GoogleSignIn/Tests/Unit/OIDAuthorizationResponse+Testing.h b/GoogleSignIn/Tests/Unit/OIDAuthorizationResponse+Testing.h index 4e15ed45..b60c88d1 100644 --- a/GoogleSignIn/Tests/Unit/OIDAuthorizationResponse+Testing.h +++ b/GoogleSignIn/Tests/Unit/OIDAuthorizationResponse+Testing.h @@ -26,6 +26,7 @@ + (instancetype)testInstanceWithAdditionalParameters: (NSDictionary *)additionalParameters + nonce:(NSString *)nonce errorString:(NSString *)errorString; @end diff --git a/GoogleSignIn/Tests/Unit/OIDAuthorizationResponse+Testing.m b/GoogleSignIn/Tests/Unit/OIDAuthorizationResponse+Testing.m index 78608b66..cc4f1211 100644 --- a/GoogleSignIn/Tests/Unit/OIDAuthorizationResponse+Testing.m +++ b/GoogleSignIn/Tests/Unit/OIDAuthorizationResponse+Testing.m @@ -25,11 +25,12 @@ @implementation OIDAuthorizationResponse (Testing) + (instancetype)testInstance { - return [self testInstanceWithAdditionalParameters:nil errorString:nil]; + return [self testInstanceWithAdditionalParameters:nil nonce:nil errorString:nil]; } + (instancetype)testInstanceWithAdditionalParameters: (NSDictionary *)additionalParameters + nonce:(NSString *)nonce errorString:(NSString *)errorString { NSMutableDictionary *parameters; @@ -45,7 +46,7 @@ + (instancetype)testInstanceWithAdditionalParameters: [parameters addEntriesFromDictionary:additionalParameters]; } } - return [[OIDAuthorizationResponse alloc] initWithRequest:[OIDAuthorizationRequest testInstance] + return [[OIDAuthorizationResponse alloc] initWithRequest:[OIDAuthorizationRequest testInstanceWithNonce:nonce] parameters:parameters]; } diff --git a/GoogleSignIn/Tests/Unit/OIDTokenResponse+Testing.m b/GoogleSignIn/Tests/Unit/OIDTokenResponse+Testing.m index 49823be7..3285ec8d 100644 --- a/GoogleSignIn/Tests/Unit/OIDTokenResponse+Testing.m +++ b/GoogleSignIn/Tests/Unit/OIDTokenResponse+Testing.m @@ -70,8 +70,7 @@ + (instancetype)testInstanceWithIDToken:(NSString *)idToken expiresIn:(NSNumber *)expiresIn refreshToken:(NSString *)refreshToken tokenRequest:(OIDTokenRequest *)tokenRequest { - NSMutableDictionary *parameters; - parameters = [[NSMutableDictionary alloc] initWithDictionary:@{ + NSMutableDictionary *parameters = [[NSMutableDictionary alloc] initWithDictionary:@{ @"access_token" : accessToken ?: kAccessToken, @"expires_in" : expiresIn ?: @(kAccessTokenExpiresIn), @"token_type" : @"example_token_type", diff --git a/Samples/ObjC/SignInSample/Podfile b/Samples/ObjC/SignInSample/Podfile index d08d7b41..ba07c279 100644 --- a/Samples/ObjC/SignInSample/Podfile +++ b/Samples/ObjC/SignInSample/Podfile @@ -1,4 +1,4 @@ -platform :ios, '11.0' +platform :ios, '12.0' use_frameworks! target 'SampleForPod' do diff --git a/Samples/ObjC/SignInSample/README.md b/Samples/ObjC/SignInSample/README.md index 82b104a4..50f9392e 100644 --- a/Samples/ObjC/SignInSample/README.md +++ b/Samples/ObjC/SignInSample/README.md @@ -18,7 +18,7 @@ open SignInSampleForPod.xcworkspace 3. Run the 'SampleForPod' target. -## Swift Pacakage Manager +## Swift Package Manager 1. In the `../Sample/ObjC/SignInSample/` folder, open the [Swift Package Manager](https://swift.org/package-manager/) project: diff --git a/Samples/ObjC/SignInSample/Source/SignInViewController.m b/Samples/ObjC/SignInSample/Source/SignInViewController.m index 4898fc8a..81ee0ed6 100644 --- a/Samples/ObjC/SignInSample/Source/SignInViewController.m +++ b/Samples/ObjC/SignInSample/Source/SignInViewController.m @@ -21,6 +21,7 @@ #import "AuthInspectorViewController.h" #import "DataPickerState.h" #import "DataPickerViewController.h" +#import static NSString *const kSignInViewTitle = @"Sign-In Sample"; static NSString *const kPlaceholderUserName = @""; @@ -247,7 +248,11 @@ - (void)updateButtons { #pragma mark - IBActions - (IBAction)signIn:(id)sender { + NSString* nonce = [OIDTokenUtilities randomURLSafeStringWithSize:32]; [GIDSignIn.sharedInstance signInWithPresentingViewController:self + hint:nil + additionalScopes:nil + nonce:nonce completion:^(GIDSignInResult *signInResult, NSError *error) { if (error) {