Skip to content

Commit 4272600

Browse files
[google_sign_in] Fix iOS sever auth codes (#10021)
Fixes an issue where `serverAuthorizationTokensForScopes` would usually return the results of `getRefreshedAuthorizationTokens` directly, even though `getRefreshedAuthorizationTokens` will never include a server auth code. Now, the server auth code is cached when it is returned from authn steps, so that it can be returned when it is requested, since those are different APIs in this plugin (unlike the underlying SDK on iOS). Fixes flutter/flutter#175313 ## Pre-Review Checklist [^1]: Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling.
1 parent f2a65fd commit 4272600

File tree

5 files changed

+355
-48
lines changed

5 files changed

+355
-48
lines changed

packages/google_sign_in/google_sign_in_ios/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## 6.2.1
2+
3+
* Fixes a bug that would cause `serverAuthorizationTokensForScopes` to
4+
return null even when called for a user that had just authenticated.
5+
16
## 6.2.0
27

38
* Adds support for the `clearAuthorizationToken` method.

packages/google_sign_in/google_sign_in_ios/lib/google_sign_in_ios.dart

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,24 @@ class GoogleSignInIOS extends GoogleSignInPlatform {
1919

2020
String? _nonce;
2121

22+
/// The last server auth code returned when authenticating or adding scopes.
23+
///
24+
/// The SDK only returns an auth code when doing a new authentication or
25+
/// when first adding new scopes; later calls to get refreshed tokens will not
26+
/// provide the server auth code again. Because this plugin separates out
27+
/// separate calls for authn, client authz, and server authz, the server auth
28+
/// token needs to be cached when it was returned so that it can be returned
29+
/// later in the session.
30+
///
31+
/// There is a small risk of returning an expired server auth token this way,
32+
/// but the plugin docs are clear that clients should obtain the server auth
33+
/// token immediately, and not rely on it continuing to be valid later.
34+
String? _cachedServerAuthCode;
35+
36+
/// The user identifier for the cached server auth code, to ensure that a
37+
/// cached code isn't returned across users.
38+
String? _cachedServerAuthCodeUserId;
39+
2240
/// Registers this class as the default instance of [GoogleSignInPlatform].
2341
static void registerWith() {
2442
GoogleSignInPlatform.instance = GoogleSignInIOS();
@@ -70,7 +88,7 @@ class GoogleSignInIOS extends GoogleSignInPlatform {
7088
Future<AuthenticationResults> authenticate(
7189
AuthenticateParameters params,
7290
) async {
73-
final SignInResult result = await _api.signIn(params.scopeHint, _nonce);
91+
final SignInResult result = await _signIn(params.scopeHint, _nonce);
7492

7593
// This should never happen; the corresponding native error code is
7694
// documented as being specific to restorePreviousSignIn.
@@ -100,6 +118,7 @@ class GoogleSignInIOS extends GoogleSignInPlatform {
100118

101119
@override
102120
Future<void> signOut(SignOutParams params) {
121+
_updateAuthCodeCache(null);
103122
return _api.signOut();
104123
}
105124

@@ -155,7 +174,7 @@ class GoogleSignInIOS extends GoogleSignInPlatform {
155174
// There's no existing sign-in to use, so return the results of the
156175
// combined authn+authz flow, if prompting is allowed.
157176
if (request.promptIfUnauthorized) {
158-
result = await _api.signIn(request.scopes, _nonce);
177+
result = await _signIn(request.scopes, _nonce);
159178
return _processAuthorizationResult(result);
160179
} else {
161180
// No existing authentication, and no prompting allowed, so return
@@ -174,7 +193,7 @@ class GoogleSignInIOS extends GoogleSignInPlatform {
174193
SignInResult result =
175194
useExistingAuthorization
176195
? await _api.getRefreshedAuthorizationTokens(userId)
177-
: await _api.addScopes(request.scopes, userId);
196+
: await _addScopes(request.scopes, userId);
178197
if (!useExistingAuthorization &&
179198
result.error?.type == GoogleSignInErrorCode.scopesAlreadyGranted) {
180199
// The Google Sign In SDK returns an error when requesting scopes that are
@@ -230,6 +249,28 @@ class GoogleSignInIOS extends GoogleSignInPlatform {
230249
return _authorizationTokenDataFromSignInSuccess(result.success);
231250
}
232251

252+
Future<SignInResult> _signIn(List<String> scopeHint, String? nonce) async {
253+
final SignInResult result = await _api.signIn(scopeHint, nonce);
254+
_updateAuthCodeCache(result.success);
255+
return result;
256+
}
257+
258+
Future<SignInResult> _addScopes(List<String> scopes, String userId) async {
259+
final SignInResult result = await _api.addScopes(scopes, userId);
260+
// Don't clear the cache for GoogleSignInErrorCode.scopesAlreadyGranted
261+
// since that indicates that nothing has changed. Otherwise, update the
262+
// cache (with a new token on success, or clearing on failure).
263+
if (result.error?.type != GoogleSignInErrorCode.scopesAlreadyGranted) {
264+
_updateAuthCodeCache(result.success);
265+
}
266+
return result;
267+
}
268+
269+
void _updateAuthCodeCache(SignInSuccess? success) {
270+
_cachedServerAuthCode = success?.serverAuthCode;
271+
_cachedServerAuthCodeUserId = success?.user.userId;
272+
}
273+
233274
AuthenticationResults _authenticationResultsFromSignInSuccess(
234275
SignInSuccess result,
235276
) {
@@ -248,9 +289,15 @@ class GoogleSignInIOS extends GoogleSignInPlatform {
248289

249290
({String? accessToken, String? serverAuthCode})
250291
_authorizationTokenDataFromSignInSuccess(SignInSuccess? result) {
292+
// Check for a relevant cached auth code to add if needed.
293+
final String? cachedAuthCode =
294+
result != null && result.user.userId == _cachedServerAuthCodeUserId
295+
? _cachedServerAuthCode
296+
: null;
297+
251298
return (
252299
accessToken: result?.accessToken,
253-
serverAuthCode: result?.serverAuthCode,
300+
serverAuthCode: result?.serverAuthCode ?? cachedAuthCode,
254301
);
255302
}
256303

packages/google_sign_in/google_sign_in_ios/pigeons/messages.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,8 @@ class SignInSuccess {
120120

121121
late List<String> grantedScopes;
122122

123-
// This is set only on a new sign in or scope grant, not a restored sign-in.
123+
// This is set only on a new sign in or scope grant, not a restored sign-in
124+
// or a call to getRefreshedAuthorizationTokens.
124125
// See https://github.com/google/GoogleSignIn-iOS/issues/202
125126
String? serverAuthCode;
126127
}

packages/google_sign_in/google_sign_in_ios/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: google_sign_in_ios
22
description: iOS implementation of the google_sign_in plugin.
33
repository: https://github.com/flutter/packages/tree/main/packages/google_sign_in/google_sign_in_ios
44
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+google_sign_in%22
5-
version: 6.2.0
5+
version: 6.2.1
66

77
environment:
88
sdk: ^3.7.0

0 commit comments

Comments
 (0)