Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

Commit a44b105

Browse files
authored
Add ability to clear auth cache on Android (#799)
1 parent aa694d4 commit a44b105

File tree

5 files changed

+53
-18
lines changed

5 files changed

+53
-18
lines changed

packages/google_sign_in/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 3.2.0
2+
3+
* Add support for clearing authentication cache for Android.
4+
15
## 3.1.0
26

37
* Add support to recover authentication for Android.

packages/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import android.accounts.Account;
88
import android.app.Activity;
99
import android.content.Intent;
10+
import com.google.android.gms.auth.GoogleAuthException;
1011
import com.google.android.gms.auth.GoogleAuthUtil;
1112
import com.google.android.gms.auth.UserRecoverableAuthException;
1213
import com.google.android.gms.auth.api.signin.GoogleSignIn;
@@ -27,6 +28,7 @@
2728
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
2829
import io.flutter.plugin.common.MethodChannel.Result;
2930
import io.flutter.plugin.common.PluginRegistry;
31+
import java.io.IOException;
3032
import java.util.HashMap;
3133
import java.util.List;
3234
import java.util.Map;
@@ -45,6 +47,7 @@ public class GoogleSignInPlugin implements MethodCallHandler {
4547
private static final String METHOD_SIGN_OUT = "signOut";
4648
private static final String METHOD_DISCONNECT = "disconnect";
4749
private static final String METHOD_IS_SIGNED_IN = "isSignedIn";
50+
private static final String METHOD_CLEAR_AUTH_CACHE = "clearAuthCache";
4851

4952
private final IDelegate delegate;
5053

@@ -86,6 +89,11 @@ public void onMethodCall(MethodCall call, Result result) {
8689
delegate.signOut(result);
8790
break;
8891

92+
case METHOD_CLEAR_AUTH_CACHE:
93+
String token = call.argument("token");
94+
delegate.clearAuthCache(result, token);
95+
break;
96+
8997
case METHOD_DISCONNECT:
9098
delegate.disconnect(result);
9199
break;
@@ -130,6 +138,12 @@ public void init(
130138
*/
131139
public void getTokens(final Result result, final String email, final boolean shouldRecoverAuth);
132140

141+
/**
142+
* Clears the token from any client cache forcing the next {@link #getTokens} call to fetch a
143+
* new one.
144+
*/
145+
public void clearAuthCache(final Result result, final String token);
146+
133147
/**
134148
* Signs the user out. Their credentials may remain valid, meaning they'll be able to silently
135149
* sign back in.
@@ -387,18 +401,15 @@ private static class PendingOperation {
387401
}
388402
}
389403

390-
private void recoverAuthFromException(final UserRecoverableAuthException exception) {
391-
registrar
392-
.activity()
393-
.runOnUiThread(
394-
new Runnable() {
395-
@Override
396-
public void run() {
397-
registrar
398-
.activity()
399-
.startActivityForResult(exception.getIntent(), REQUEST_CODE_RECOVER_AUTH);
400-
}
401-
});
404+
/** Clears the token kept in the client side cache. */
405+
@Override
406+
public void clearAuthCache(Result result, String token) {
407+
try {
408+
GoogleAuthUtil.clearToken(registrar.context(), token);
409+
result.success(null);
410+
} catch (GoogleAuthException | IOException e) {
411+
result.error(ERROR_REASON_EXCEPTION, e.getMessage(), e);
412+
}
402413
}
403414

404415
/**
@@ -411,8 +422,6 @@ public void run() {
411422
@Override
412423
public void getTokens(
413424
final Result result, final String email, final boolean shouldRecoverAuth) {
414-
// TODO(issue/11107): Add back the checkAndSetPendingOperation once getTokens is properly
415-
// gated from Dart code. Change result.success/error calls below to use finishWith()
416425
if (email == null) {
417426
result.error(ERROR_REASON_EXCEPTION, "Email is null", null);
418427
return;
@@ -428,6 +437,9 @@ public String call() throws Exception {
428437
}
429438
};
430439

440+
// Background task runner has a single thread effectively serializing
441+
// the getToken calls. 1p apps can then enjoy the token cache if multiple
442+
// getToken calls are coming in.
431443
backgroundTaskRunner.runInBackground(
432444
getTokenTask,
433445
new BackgroundTaskRunner.Callback<String>() {
@@ -440,10 +452,13 @@ public void run(Future<String> tokenFuture) {
440452
result.success(tokenResult);
441453
} catch (ExecutionException e) {
442454
if (e.getCause() instanceof UserRecoverableAuthException) {
443-
if (shouldRecoverAuth) {
444-
// Move this to top of getTokens method.
455+
if (shouldRecoverAuth && pendingOperation == null) {
445456
checkAndSetPendingOperation(METHOD_GET_TOKENS, result, email);
446-
recoverAuthFromException((UserRecoverableAuthException) e.getCause());
457+
Intent recoveryIntent =
458+
((UserRecoverableAuthException) e.getCause()).getIntent();
459+
registrar
460+
.activity()
461+
.startActivityForResult(recoveryIntent, REQUEST_CODE_RECOVER_AUTH);
447462
} else {
448463
result.error(ERROR_USER_RECOVERABLE_AUTH, e.getLocalizedMessage(), null);
449464
}

packages/google_sign_in/ios/Classes/GoogleSignInPlugin.m

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,10 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result
113113
if ([self setAccountRequest:result]) {
114114
[[GIDSignIn sharedInstance] disconnect];
115115
}
116+
} else if ([call.method isEqualToString:@"clearAuthCache"]) {
117+
// There's nothing to be done here on iOS since the expired/invalid
118+
// tokens are refreshed automatically by getTokensWithHandler.
119+
result(nil);
116120
} else {
117121
result(FlutterMethodNotImplemented);
118122
}

packages/google_sign_in/lib/google_sign_in.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,18 @@ class GoogleSignInAccount implements GoogleIdentity {
102102
};
103103
}
104104

105+
/// Clears any client side cache that might be holding invalid tokens.
106+
///
107+
/// If client runs into 401 errors using a token, it is expected to call
108+
/// this method and grab `authHeaders` once again.
109+
Future<void> clearAuthCache() async {
110+
final String token = (await authentication).accessToken;
111+
await GoogleSignIn.channel.invokeMethod(
112+
'clearAuthCache',
113+
<String, dynamic>{'token': token},
114+
);
115+
}
116+
105117
@override
106118
bool operator ==(dynamic other) {
107119
if (identical(this, other)) return true;

packages/google_sign_in/pubspec.yaml

Lines changed: 1 addition & 1 deletion
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 on Android and iOS.
44
author: Flutter Team <[email protected]>
55
homepage: https://github.com/flutter/plugins/tree/master/packages/google_sign_in
6-
version: 3.1.0
6+
version: 3.2.0
77

88
flutter:
99
plugin:

0 commit comments

Comments
 (0)