diff --git a/packages/google_sign_in/google_sign_in_ios/CHANGELOG.md b/packages/google_sign_in/google_sign_in_ios/CHANGELOG.md index fae9e92a608f..96d8d81e260a 100644 --- a/packages/google_sign_in/google_sign_in_ios/CHANGELOG.md +++ b/packages/google_sign_in/google_sign_in_ios/CHANGELOG.md @@ -1,3 +1,8 @@ +## 6.3.1 + +* Fixes a bug that would cause `authorizeServer` to throw a `PlatformException` + due to an expired or revoked token. + ## 6.3.0 * Adds UIScene compatibility. diff --git a/packages/google_sign_in/google_sign_in_ios/lib/google_sign_in_ios.dart b/packages/google_sign_in/google_sign_in_ios/lib/google_sign_in_ios.dart index 2f11c953e5b6..b68bb58a0654 100644 --- a/packages/google_sign_in/google_sign_in_ios/lib/google_sign_in_ios.dart +++ b/packages/google_sign_in/google_sign_in_ios/lib/google_sign_in_ios.dart @@ -170,7 +170,15 @@ class GoogleSignInIOS extends GoogleSignInPlatform { // if the authentication isn't associated with an existing sign-in user // run the authentication flow first. if (userId == null) { - SignInResult result = await _api.restorePreviousSignIn(); + SignInResult result; + try { + result = await _api.restorePreviousSignIn(); + } on Exception { + // This can throw if the token has expired or been revoked. + // e.g. PlatformException(org.openid.appauth.oauth_token: -10, invalid_grant: Token has been expired or revoked.) + result = SignInResult(error: SignInFailure(type: .unknown)); + } + final SignInSuccess? success = result.success; if (success == null) { // There's no existing sign-in to use, so return the results of the diff --git a/packages/google_sign_in/google_sign_in_ios/pubspec.yaml b/packages/google_sign_in/google_sign_in_ios/pubspec.yaml index c59465512615..4484e289128b 100644 --- a/packages/google_sign_in/google_sign_in_ios/pubspec.yaml +++ b/packages/google_sign_in/google_sign_in_ios/pubspec.yaml @@ -2,7 +2,7 @@ name: google_sign_in_ios description: iOS implementation of the google_sign_in plugin. repository: https://github.com/flutter/packages/tree/main/packages/google_sign_in/google_sign_in_ios issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+google_sign_in%22 -version: 6.3.0 +version: 6.3.1 environment: sdk: ^3.10.0 diff --git a/packages/google_sign_in/google_sign_in_ios/test/google_sign_in_ios_test.dart b/packages/google_sign_in/google_sign_in_ios/test/google_sign_in_ios_test.dart index c39b626591c3..b123b2f6e675 100644 --- a/packages/google_sign_in/google_sign_in_ios/test/google_sign_in_ios_test.dart +++ b/packages/google_sign_in/google_sign_in_ios/test/google_sign_in_ios_test.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:google_sign_in_ios/google_sign_in_ios.dart'; import 'package:google_sign_in_ios/src/messages.g.dart'; @@ -915,6 +916,52 @@ void main() { }, ); + test( + 'attempts to authenticate if tokens have expired or been revoked', + () async { + const scopes = ['a', 'b']; + when(mockApi.restorePreviousSignIn()).thenThrow( + PlatformException( + code: 'org.openid.appauth.oauth_token: -10', + message: 'invalid_grant: Token has been expired or revoked.', + ), + ); + when(mockApi.signIn(scopes, null)).thenAnswer( + (_) async => SignInResult( + success: SignInSuccess( + user: UserData( + displayName: _testUser.displayName, + email: _testUser.email, + userId: _testUser.id, + photoUrl: _testUser.photoUrl, + idToken: '', + ), + accessToken: '', + grantedScopes: [], + ), + ), + ); + + await googleSignIn.serverAuthorizationTokensForScopes( + const ServerAuthorizationTokensForScopesParameters( + request: AuthorizationRequestDetails( + scopes: scopes, + userId: null, + email: null, + promptIfUnauthorized: true, + ), + ), + ); + + // With no user ID provided to serverAuthorizationTokensForScopes, the + // implementation should attempt to restore an existing sign-in, and then + // when that throws due to an expired/revoked token, prompt for a combined authn+authz. + // https://github.com/flutter/flutter/issues/184134 + verify(mockApi.restorePreviousSignIn()); + verify(mockApi.signIn(scopes, null)); + }, + ); + test('attempts to authenticate if no user is provided or already signed in ' 'and interaction is allowed', () async { const scopes = ['a', 'b'];