Skip to content

Commit f2a65fd

Browse files
[google_sign_in] Add a method to clear auth tokens (#9846)
Adds a new `clearAuthorizationToken` method to all layers of the plugin stack, allowing for removing a token from the cache: - On Android, this calls a very recently added `AuthorizationClient` method that was added for this purpose. - On Web it deletes tokens from our own cache. - On iOS, it's a no-op since this is managed internally. Originally I hadn't thought this was necessary since all platform manage token expiration automatically, but as the linked issue highlights there are cases where a non-expired token can become invalid, and in that case it will sit in the cache and continue to be returned on Android and Web. Clients are expected to handle this case when API requests using the token fail ([example docs for Android](https://developer.android.com/identity/authorization#clear-token-cache)), so we need to provide a method for it. Fixes flutter/flutter#173924 ## Pre-Review Checklist **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. [^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 f7af7c2 commit f2a65fd

File tree

7 files changed

+75
-18
lines changed

7 files changed

+75
-18
lines changed

packages/google_sign_in/google_sign_in/CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
## NEXT
1+
## 7.2.0
22

3+
* Adds a `clearAuthorizationToken` method to remove an access token from the
4+
cache.
35
* Updates minimum supported SDK version to Flutter 3.29/Dart 3.7.
46

57
## 7.1.1

packages/google_sign_in/google_sign_in/MIGRATION.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ include:
6161
publishing, the only platform that does not support `authenticate` is web,
6262
where `google_sign_in_web`'s `renderButton` is used to create a sign-in
6363
button.
64+
* `clearAuthCache` has been replaced by `clearAuthorizationToken`.
6465
* Outcomes other than successful authentication or authorization will throw
6566
`GoogleSignInException`s in most cases, allowing a clear way to distinguish
6667
different sign in failure outcomes. This includes the user canceling

packages/google_sign_in/google_sign_in/example/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ dependencies:
1616
# The example app is bundled with the plugin so we use a path dependency on
1717
# the parent directory to use the current plugin's version.
1818
path: ../
19-
google_sign_in_web: ^1.0.0
19+
google_sign_in_web: ^1.1.0
2020
http: ">=0.13.0 <2.0.0"
2121

2222
dev_dependencies:

packages/google_sign_in/google_sign_in/lib/google_sign_in.dart

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,9 @@ class GoogleSignInAuthorizationClient {
136136
///
137137
/// If authorization would require user interaction, this returns null, in
138138
/// which case [authorizeScopes] should be used instead.
139+
///
140+
/// In rare cases, this can return tokens that are no longer valid. See
141+
/// [clearAuthorizationToken] for details.
139142
Future<GoogleSignInClientAuthorization?> authorizationForScopes(
140143
List<String> scopes,
141144
) async {
@@ -150,6 +153,9 @@ class GoogleSignInAuthorizationClient {
150153
/// allowed (for example, while the app is foregrounded on mobile), and if
151154
/// [GoogleSignIn.authorizationRequiresUserInteraction] returns true this
152155
/// should only be called from an user interaction handler.
156+
///
157+
/// In rare cases, this can return tokens that are no longer valid. See
158+
/// [clearAuthorizationToken] for details.
153159
Future<GoogleSignInClientAuthorization> authorizeScopes(
154160
List<String> scopes,
155161
) async {
@@ -173,8 +179,10 @@ class GoogleSignInAuthorizationClient {
173179
/// authorization headers, containing the access token for the given scopes.
174180
///
175181
/// Returns null if the given scopes are not authorized, or there is no
176-
/// currently valid authorization token available, and
177-
/// [promptIfNecessary] is false.
182+
/// unexpired authorization token available, and [promptIfNecessary] is false.
183+
///
184+
/// In rare cases, this can return tokens that are no longer valid. See
185+
/// [clearAuthorizationToken] for details.
178186
///
179187
/// See also https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization.
180188
Future<Map<String, String>?> authorizationHeaders(
@@ -207,6 +215,9 @@ class GoogleSignInAuthorizationClient {
207215
/// allowed (for example, while the app is foregrounded on mobile), and if
208216
/// [GoogleSignIn.authorizationRequiresUserInteraction] returns true this
209217
/// should only be called from an user interaction handler.
218+
///
219+
/// In rare cases, this can return tokens that are no longer valid. See
220+
/// [clearAuthorizationToken] for details.
210221
Future<GoogleSignInServerAuthorization?> authorizeServer(
211222
List<String> scopes,
212223
) async {
@@ -229,6 +240,20 @@ class GoogleSignInAuthorizationClient {
229240
);
230241
}
231242

243+
/// Removes the given [accessToken] from any local authorization caches.
244+
///
245+
/// This should be called if using an access token results in an invalid token
246+
/// response from the target API, followed by re-requsting authorization.
247+
///
248+
/// A token can be invalidated by, for example, a user removing an
249+
/// application's authorization from outside of the application:
250+
/// https://support.google.com/accounts/answer/13533235.
251+
Future<void> clearAuthorizationToken({required String accessToken}) {
252+
return GoogleSignInPlatform.instance.clearAuthorizationToken(
253+
ClearAuthorizationTokenParams(accessToken: accessToken),
254+
);
255+
}
256+
232257
Future<GoogleSignInClientAuthorization?> _authorizeClient(
233258
List<String> scopes, {
234259
required bool promptIfUnauthorized,

packages/google_sign_in/google_sign_in/pubspec.yaml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ description: Flutter plugin for Google Sign-In, a secure authentication system
33
for signing in with a Google account.
44
repository: https://github.com/flutter/packages/tree/main/packages/google_sign_in/google_sign_in
55
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+google_sign_in%22
6-
version: 7.1.1
6+
version: 7.2.0
77

88
environment:
99
sdk: ^3.7.0
@@ -24,10 +24,10 @@ flutter:
2424
dependencies:
2525
flutter:
2626
sdk: flutter
27-
google_sign_in_android: ^7.0.0
28-
google_sign_in_ios: ^6.0.0
29-
google_sign_in_platform_interface: ^3.0.0
30-
google_sign_in_web: ^1.0.0
27+
google_sign_in_android: ^7.1.0
28+
google_sign_in_ios: ^6.2.0
29+
google_sign_in_platform_interface: ^3.1.0
30+
google_sign_in_web: ^1.1.0
3131

3232
dev_dependencies:
3333
build_runner: ^2.1.10

packages/google_sign_in/google_sign_in/test/google_sign_in_test.dart

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -760,4 +760,22 @@ void main() {
760760
);
761761
});
762762
});
763+
764+
group('clearAuthorizationToken', () {
765+
test('passes expected paramaters', () async {
766+
final GoogleSignIn googleSignIn = GoogleSignIn.instance;
767+
768+
const String token = 'someAccessToken';
769+
await googleSignIn.authorizationClient.clearAuthorizationToken(
770+
accessToken: token,
771+
);
772+
773+
final VerificationResult verification = verify(
774+
mockPlatform.clearAuthorizationToken(captureAny),
775+
);
776+
final ClearAuthorizationTokenParams params =
777+
verification.captured[0] as ClearAuthorizationTokenParams;
778+
expect(params.accessToken, token);
779+
});
780+
});
763781
}

packages/google_sign_in/google_sign_in/test/google_sign_in_test.mocks.dart

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Mocks generated by Mockito 5.4.5 from annotations
1+
// Mocks generated by Mockito 5.4.6 from annotations
22
// in google_sign_in/test/google_sign_in_test.dart.
33
// Do not manually edit this file.
44

@@ -57,6 +57,14 @@ class MockGoogleSignInPlatform extends _i1.Mock
5757
)
5858
as _i4.Future<_i2.AuthenticationResults?>?);
5959

60+
@override
61+
bool supportsAuthenticate() =>
62+
(super.noSuchMethod(
63+
Invocation.method(#supportsAuthenticate, []),
64+
returnValue: false,
65+
)
66+
as bool);
67+
6068
@override
6169
_i4.Future<_i2.AuthenticationResults> authenticate(
6270
_i2.AuthenticateParameters? params,
@@ -72,14 +80,6 @@ class MockGoogleSignInPlatform extends _i1.Mock
7280
)
7381
as _i4.Future<_i2.AuthenticationResults>);
7482

75-
@override
76-
bool supportsAuthenticate() =>
77-
(super.noSuchMethod(
78-
Invocation.method(#supportsAuthenticate, []),
79-
returnValue: false,
80-
)
81-
as bool);
82-
8383
@override
8484
bool authorizationRequiresUserInteraction() =>
8585
(super.noSuchMethod(
@@ -110,6 +110,17 @@ class MockGoogleSignInPlatform extends _i1.Mock
110110
)
111111
as _i4.Future<_i2.ServerAuthorizationTokenData?>);
112112

113+
@override
114+
_i4.Future<void> clearAuthorizationToken(
115+
_i2.ClearAuthorizationTokenParams? params,
116+
) =>
117+
(super.noSuchMethod(
118+
Invocation.method(#clearAuthorizationToken, [params]),
119+
returnValue: _i4.Future<void>.value(),
120+
returnValueForMissingStub: _i4.Future<void>.value(),
121+
)
122+
as _i4.Future<void>);
123+
113124
@override
114125
_i4.Future<void> signOut(_i2.SignOutParams? params) =>
115126
(super.noSuchMethod(

0 commit comments

Comments
 (0)