@@ -41,6 +41,8 @@ class GisSdkClient {
41
41
_initializeIdClient (
42
42
clientId,
43
43
onResponse: _onCredentialResponse,
44
+ hostedDomain: hostedDomain,
45
+ useFedCM: true ,
44
46
);
45
47
46
48
_tokenClient = _initializeTokenClient (
@@ -64,6 +66,8 @@ class GisSdkClient {
64
66
65
67
_tokenResponses.stream.listen ((TokenResponse response) {
66
68
_lastTokenResponse = response;
69
+ _lastTokenResponseExpiration =
70
+ DateTime .now ().add (Duration (seconds: response.expires_in));
67
71
}, onError: (Object error) {
68
72
_logIfEnabled ('Error on TokenResponse:' , < Object > [error.toString ()]);
69
73
_lastTokenResponse = null ;
@@ -102,13 +106,18 @@ class GisSdkClient {
102
106
void _initializeIdClient (
103
107
String clientId, {
104
108
required CallbackFn onResponse,
109
+ String ? hostedDomain,
110
+ bool ? useFedCM,
105
111
}) {
106
112
// Initialize `id` for the silent-sign in code.
107
113
final IdConfiguration idConfig = IdConfiguration (
108
114
client_id: clientId,
109
115
callback: allowInterop (onResponse),
110
116
cancel_on_tap_outside: false ,
111
117
auto_select: true , // Attempt to sign-in silently.
118
+ hd: hostedDomain,
119
+ use_fedcm_for_prompt:
120
+ useFedCM, // Use the native browser prompt, when available.
112
121
);
113
122
id.initialize (idConfig);
114
123
}
@@ -230,6 +239,8 @@ class GisSdkClient {
230
239
return id.renderButton (parent, convertButtonConfiguration (options)! );
231
240
}
232
241
242
+ // TODO(dit): Clean this up. https://github.com/flutter/flutter/issues/137727
243
+ //
233
244
/// Starts an oauth2 "implicit" flow to authorize requests.
234
245
///
235
246
/// The new GIS SDK does not return user authentication from this flow, so:
@@ -238,7 +249,15 @@ class GisSdkClient {
238
249
/// * If [_lastCredentialResponse] is null, we add [people.scopes] to the
239
250
/// [_initialScopes], so we can retrieve User Profile information back
240
251
/// from the People API (without idToken). See [people.requestUserData].
252
+ @Deprecated (
253
+ 'Use `renderButton` instead. See: https://pub.dev/packages/google_sign_in_web#migrating-to-v011-and-v012-google-identity-services' )
241
254
Future <GoogleSignInUserData ?> signIn () async {
255
+ // Warn users that this method will be removed.
256
+ domConsole.warn (
257
+ 'The google_sign_in plugin `signIn` method is deprecated on the web, and will be removed in Q2 2024. Please use `renderButton` instead. See: ' ,
258
+ < String > [
259
+ 'https://pub.dev/packages/google_sign_in_web#migrating-to-v011-and-v012-google-identity-services'
260
+ ]);
242
261
// If we already know the user, use their `email` as a `hint`, so they don't
243
262
// have to pick their user again in the Authorization popup.
244
263
final GoogleSignInUserData ? knownUser =
@@ -265,6 +284,8 @@ class GisSdkClient {
265
284
// This function returns the currently signed-in [GoogleSignInUserData].
266
285
//
267
286
// It'll do a request to the People API (if needed).
287
+ //
288
+ // TODO(dit): Clean this up. https://github.com/flutter/flutter/issues/137727
268
289
Future <GoogleSignInUserData ?> _computeUserDataForLastToken () async {
269
290
// If the user hasn't authenticated, request their basic profile info
270
291
// from the People API.
@@ -302,9 +323,27 @@ class GisSdkClient {
302
323
await signOut ();
303
324
}
304
325
305
- /// Returns true if the client has recognized this user before.
326
+ /// Returns true if the client has recognized this user before, and the last-seen
327
+ /// credential is not expired.
306
328
Future <bool > isSignedIn () async {
307
- return _lastCredentialResponse != null || _requestedUserData != null ;
329
+ bool isSignedIn = false ;
330
+ if (_lastCredentialResponse != null ) {
331
+ final DateTime ? expiration = utils
332
+ .getCredentialResponseExpirationTimestamp (_lastCredentialResponse);
333
+ // All Google ID Tokens provide an "exp" date. If the method above cannot
334
+ // extract `expiration`, it's because `_lastCredentialResponse`'s contents
335
+ // are unexpected (or wrong) in any way.
336
+ //
337
+ // Users are considered to be signedIn when the last CredentialResponse
338
+ // exists and has an expiration date in the future.
339
+ //
340
+ // Users are not signed in in any other case.
341
+ //
342
+ // See: https://developers.google.com/identity/openid-connect/openid-connect#an-id-tokens-payload
343
+ isSignedIn = expiration? .isAfter (DateTime .now ()) ?? false ;
344
+ }
345
+
346
+ return isSignedIn || _requestedUserData != null ;
308
347
}
309
348
310
349
/// Clears all the cached results from authentication and authorization.
@@ -338,12 +377,15 @@ class GisSdkClient {
338
377
/// Checks if the passed-in `accessToken` can access all `scopes` .
339
378
///
340
379
/// This validates that the `accessToken` is the same as the last seen
341
- /// token response, and uses that response to check if permissions are
342
- /// still granted.
380
+ /// token response, that the token is not expired, then uses that response to
381
+ /// check if permissions are still granted.
343
382
Future <bool > canAccessScopes (List <String > scopes, String ? accessToken) async {
344
383
if (accessToken != null && _lastTokenResponse != null ) {
345
384
if (accessToken == _lastTokenResponse! .access_token) {
346
- return oauth2.hasGrantedAllScopes (_lastTokenResponse! , scopes);
385
+ final bool isTokenValid =
386
+ _lastTokenResponseExpiration? .isAfter (DateTime .now ()) ?? false ;
387
+ return isTokenValid &&
388
+ oauth2.hasGrantedAllScopes (_lastTokenResponse! , scopes);
347
389
}
348
390
}
349
391
return false ;
@@ -368,6 +410,8 @@ class GisSdkClient {
368
410
// The last-seen credential and token responses
369
411
CredentialResponse ? _lastCredentialResponse;
370
412
TokenResponse ? _lastTokenResponse;
413
+ // Expiration timestamp for the lastTokenResponse, which only has an `expires_in` field.
414
+ DateTime ? _lastTokenResponseExpiration;
371
415
372
416
/// The StreamController onto which the GIS Client propagates user authentication events.
373
417
///
@@ -379,5 +423,7 @@ class GisSdkClient {
379
423
// (if needed)
380
424
//
381
425
// (This is a synthetic _lastCredentialResponse)
426
+ //
427
+ // TODO(dit): Clean this up. https://github.com/flutter/flutter/issues/137727
382
428
GoogleSignInUserData ? _requestedUserData;
383
429
}
0 commit comments