Skip to content

[extension_google_sign_in_as_googleapis_auth] Update to google_sign_in 7 #9484

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
## NEXT

## 3.0.0

* **BREAKING CHANGES**:
* The extension method is now on `GoogleSignInClientAuthorization` instead of
`GoogleSignIn`, so it must be used after completing an authorization flow.
* The extension method has been renamed to `authClient`.
* The extension method now requires passing `scopes`, matching those used to
request the authorization.
* Updates minimum supported SDK version to Flutter 3.27/Dart 3.6.

## 2.0.13
Expand Down
26 changes: 13 additions & 13 deletions packages/extension_google_sign_in_as_googleapis_auth/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,19 @@ That object can then be used to create instances of `googleapis` API clients:

<?code-excerpt "example/lib/main.dart (CreateAPIClient)"?>
```dart
// Retrieve an [auth.AuthClient] from the current [GoogleSignIn] instance.
final auth.AuthClient? client = await _googleSignIn.authenticatedClient();
assert(client != null, 'Authenticated client missing!');
// Prepare a People Service authenticated client.
final PeopleServiceApi peopleApi = PeopleServiceApi(client!);
// Retrieve a list of the `names` of my `connections`
final ListConnectionsResponse response =
await peopleApi.people.connections.list(
'people/me',
personFields: 'names',
);
import 'package:googleapis_auth/googleapis_auth.dart' as auth show AuthClient;
// ···
// Retrieve an [auth.AuthClient] from a GoogleSignInClientAuthorization.
final auth.AuthClient client = authorization.authClient(scopes: scopes);
// Prepare a People Service authenticated client.
final PeopleServiceApi peopleApi = PeopleServiceApi(client);
// Retrieve a list of connected contacts' names.
final ListConnectionsResponse response =
await peopleApi.people.connections.list(
'people/me',
personFields: 'names',
);
```

## Example
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,12 @@ import 'package:extension_google_sign_in_as_googleapis_auth/extension_google_sig
import 'package:flutter/material.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:googleapis/people/v1.dart';
// #docregion CreateAPIClient
import 'package:googleapis_auth/googleapis_auth.dart' as auth show AuthClient;
// #enddocregion CreateAPIClient

final GoogleSignIn _googleSignIn = GoogleSignIn(
// Optional clientId
// clientId: '[YOUR_OAUTH_2_CLIENT_ID]',
scopes: <String>[PeopleServiceApi.contactsReadonlyScope],
);
/// The scopes used by this example.
const List<String> scopes = <String>[PeopleServiceApi.contactsReadonlyScope];

void main() {
runApp(
Expand All @@ -38,37 +37,84 @@ class SignInDemo extends StatefulWidget {

/// The state of the main widget.
class SignInDemoState extends State<SignInDemo> {
late Future<void> _signInInitialized;
GoogleSignInAccount? _currentUser;
GoogleSignInClientAuthorization? _authorization;
String _contactText = '';

@override
void initState() {
super.initState();
_googleSignIn.onCurrentUserChanged.listen((GoogleSignInAccount? account) {

final GoogleSignIn signIn = GoogleSignIn.instance;
_signInInitialized = signIn.initialize(
// Add your client IDs here as necessary for your supported platforms.
);
signIn.authenticationEvents.listen((GoogleSignInAuthenticationEvent event) {
if (!mounted) {
return;
}
setState(() {
_currentUser = account;
switch (event) {
case GoogleSignInAuthenticationEventSignIn():
_currentUser = event.user;
case GoogleSignInAuthenticationEventSignOut():
_currentUser = null;
_authorization = null;
}
});

if (_currentUser != null) {
_handleGetContact();
_checkAuthorization();
}
}).onError((Object error) {
debugPrint(error.toString());
});

_signInInitialized.then((void value) {
signIn.attemptLightweightAuthentication();
});
_googleSignIn.signInSilently();
}

Future<void> _handleGetContact() async {
void _updateAuthorization(GoogleSignInClientAuthorization? authorization) {
if (!mounted) {
return;
}
setState(() {
_contactText = 'Loading contact info...';
_authorization = authorization;
});

// #docregion CreateAPIClient
// Retrieve an [auth.AuthClient] from the current [GoogleSignIn] instance.
final auth.AuthClient? client = await _googleSignIn.authenticatedClient();
if (authorization != null) {
unawaited(_handleGetContact(authorization));
}
}

assert(client != null, 'Authenticated client missing!');
Future<void> _checkAuthorization() async {
_updateAuthorization(
await _currentUser?.authorizationClient.authorizationForScopes(scopes));
}

Future<void> _requestAuthorization() async {
_updateAuthorization(await _currentUser?.authorizationClient
.authorizeScopes(<String>[PeopleServiceApi.contactsReadonlyScope]));
}

Future<void> _handleGetContact(
GoogleSignInClientAuthorization authorization) async {
if (!mounted) {
return;
}
setState(() {
_contactText = 'Loading contact info...';
});

// #docregion CreateAPIClient
// Retrieve an [auth.AuthClient] from a GoogleSignInClientAuthorization.
final auth.AuthClient client = authorization.authClient(scopes: scopes);

// Prepare a People Service authenticated client.
final PeopleServiceApi peopleApi = PeopleServiceApi(client!);
// Retrieve a list of the `names` of my `connections`
final PeopleServiceApi peopleApi = PeopleServiceApi(client);
// Retrieve a list of connected contacts' names.
final ListConnectionsResponse response =
await peopleApi.people.connections.list(
'people/me',
Expand All @@ -79,13 +125,15 @@ class SignInDemoState extends State<SignInDemo> {
final String? firstNamedContactName =
_pickFirstNamedContact(response.connections);

setState(() {
if (firstNamedContactName != null) {
_contactText = 'I see you know $firstNamedContactName!';
} else {
_contactText = 'No contacts to display.';
}
});
if (mounted) {
setState(() {
if (firstNamedContactName != null) {
_contactText = 'I see you know $firstNamedContactName!';
} else {
_contactText = 'No contacts to display.';
}
});
}
}

String? _pickFirstNamedContact(List<Person>? connections) {
Expand All @@ -102,51 +150,72 @@ class SignInDemoState extends State<SignInDemo> {

Future<void> _handleSignIn() async {
try {
await _googleSignIn.signIn();
await GoogleSignIn.instance.authenticate();
} catch (error) {
print(error); // ignore: avoid_print
debugPrint(error.toString());
}
}

Future<void> _handleSignOut() => _googleSignIn.disconnect();
// Call disconnect rather than signOut to more fully reset the example app.
Future<void> _handleSignOut() => GoogleSignIn.instance.disconnect();

Widget _buildBody() {
final GoogleSignInAccount? user = _currentUser;
if (user != null) {
return Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
ListTile(
leading: GoogleUserCircleAvatar(
identity: user,
),
title: Text(user.displayName ?? ''),
subtitle: Text(user.email),
),
const Text('Signed in successfully.'),
Text(_contactText),
ElevatedButton(
onPressed: _handleSignOut,
child: const Text('SIGN OUT'),
),
ElevatedButton(
onPressed: _handleGetContact,
child: const Text('REFRESH'),
),
],
);
} else {
return Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
const Text('You are not currently signed in.'),
ElevatedButton(
onPressed: _handleSignIn,
child: const Text('SIGN IN'),
),
],
);
}
return FutureBuilder<void>(
future: _signInInitialized,
builder: (BuildContext context, AsyncSnapshot<void> snapshot) {
final GoogleSignInAccount? user = _currentUser;
final GoogleSignInClientAuthorization? authorization = _authorization;
final List<Widget> children;
if (snapshot.hasError) {
children = <Widget>[
const Text('Error initializing sign in.'),
];
} else if (snapshot.connectionState == ConnectionState.done) {
children = <Widget>[
if (user != null) ...<Widget>[
ListTile(
leading: GoogleUserCircleAvatar(
identity: user,
),
title: Text(user.displayName ?? ''),
subtitle: Text(user.email),
),
const Text('Signed in successfully.'),
if (authorization != null) ...<Widget>[
Text(_contactText),
ElevatedButton(
onPressed: () => _handleGetContact(authorization),
child: const Text('REFRESH'),
),
] else ...<Widget>[
ElevatedButton(
onPressed: _requestAuthorization,
child: const Text('LOAD CONTACTS'),
),
],
ElevatedButton(
onPressed: _handleSignOut,
child: const Text('SIGN OUT'),
),
] else ...<Widget>[
const Text('You are not currently signed in.'),
ElevatedButton(
onPressed: _handleSignIn,
child: const Text('SIGN IN'),
),
],
];
} else {
children = <Widget>[
const CircularProgressIndicator(),
];
}

return Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: children,
);
});
}

@override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ dependencies:
path: ../
flutter:
sdk: flutter
google_sign_in: ^6.0.0
google_sign_in: ^7.0.0
googleapis: ">=10.1.0 <14.0.0"
googleapis_auth: ^1.1.0

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,29 @@
import 'package:google_sign_in/google_sign_in.dart';
import 'package:googleapis_auth/googleapis_auth.dart' as gapis;
import 'package:http/http.dart' as http;
import 'package:meta/meta.dart';

/// Extension on [GoogleSignIn] that adds an `authenticatedClient` method.
///
/// This method can be used to retrieve an authenticated [gapis.AuthClient]
/// client that can be used with the rest of the `googleapis` libraries.
extension GoogleApisGoogleSignInAuth on GoogleSignIn {
/// Retrieve a `googleapis` authenticated client.
Future<gapis.AuthClient?> authenticatedClient({
@visibleForTesting GoogleSignInAuthentication? debugAuthentication,
@visibleForTesting List<String>? debugScopes,
}) async {
final GoogleSignInAuthentication? auth =
debugAuthentication ?? await currentUser?.authentication;
final String? oauthTokenString = auth?.accessToken;
if (oauthTokenString == null) {
return null;
}
/// Extension on [GoogleSignInClientAuthorization] that adds an
/// `authClient` method.
extension GoogleApisGoogleSignInAuth on GoogleSignInClientAuthorization {
/// Returns an authenticated [gapis.AuthClient] client that can be used with
/// the rest of the `googleapis` libraries.
///
/// The [scopes] passed here should be the same as the scopes used to request
/// the authorization. Passing scopes here that have not been authorized will
/// likely result in API errors when using the client.
gapis.AuthClient authClient({
required List<String> scopes,
}) {
final gapis.AccessCredentials credentials = gapis.AccessCredentials(
gapis.AccessToken(
'Bearer',
oauthTokenString,
// TODO(kevmoo): Use the correct value once it's available from authentication
// See https://github.com/flutter/flutter/issues/80905
accessToken,
// The underlying SDKs don't provide expiry information, so set an
// arbitrary distant-future time.
DateTime.now().toUtc().add(const Duration(days: 365)),
),
null, // We don't have a refreshToken
debugScopes ?? scopes,
null, // The underlying SDKs don't provide a refresh token.
scopes,
);

return gapis.authenticatedClient(http.Client(), credentials);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ name: extension_google_sign_in_as_googleapis_auth
description: A bridge package between google_sign_in and googleapis_auth, to create Authenticated Clients from google_sign_in user credentials.
repository: https://github.com/flutter/packages/tree/main/packages/extension_google_sign_in_as_googleapis_auth
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+extension_google_sign_in_as_googleapis_auth%22
version: 2.0.13
version: 3.0.0

environment:
sdk: ^3.6.0
Expand All @@ -17,7 +17,7 @@ environment:
dependencies:
flutter:
sdk: flutter
google_sign_in: ">=5.0.0 <7.0.0"
google_sign_in: ^7.0.0
googleapis_auth: '>=1.1.0 <3.0.0'
http: ">=0.13.0 <2.0.0"
meta: ^1.3.0
Expand Down
Loading