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

[google_sign_in_web] Migrate to the GIS SDK. #6921

Merged
merged 31 commits into from
Feb 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
bb67b77
[google_sign_in_web] Migrate to GIS SDK.
ditman Jan 7, 2023
095feaf
include_granted_scopes in requestScopes call.
ditman Jan 7, 2023
60ffbb3
Remove the old JS-interop layer.
ditman Jan 11, 2023
66cebf3
Introduce a mockable GisSdkClient for tests.
ditman Jan 12, 2023
1e88f00
Split the people utils.
ditman Jan 12, 2023
7f3b281
Delete tests for the old code.
ditman Jan 12, 2023
c77e6d3
Add some tests for the new code.
ditman Jan 12, 2023
bbe2349
More utils_test.dart
ditman Jan 13, 2023
77fb227
Make jsifyAs reusable.
ditman Jan 13, 2023
552d7b3
Ignore the tester in utils_test.dart
ditman Jan 17, 2023
060a11d
Make Clients overridable, and some renaming.
ditman Jan 17, 2023
17e73fa
Test people.dart
ditman Jan 17, 2023
55ff6ac
Make autoDetectedClientId more testable.
ditman Jan 17, 2023
203ae47
Add mockito.
ditman Jan 17, 2023
e41c012
Comment about where to better split the code so GisSdkClient is testa…
ditman Jan 17, 2023
138f5f3
Add google_sign_in_web_test.dart (and its mocks)
ditman Jan 18, 2023
16d0843
dart format
ditman Jan 18, 2023
0fc3c98
Log only in debug.
ditman Jan 18, 2023
5bfcec5
Sync min sdk with package gis_web
ditman Jan 18, 2023
8bee18b
Add migration notes to the README.
ditman Jan 28, 2023
c7a9a32
When the user is known upon signIn, remove friction.
ditman Jan 28, 2023
6e60484
Address PR comments / checks.
ditman Jan 28, 2023
f1e55aa
Update migration guide after comments from testers.
ditman Jan 28, 2023
e9efdd6
Update README.md
ditman Feb 14, 2023
85218f4
Remove package:jose from tests.
ditman Feb 14, 2023
0a70e21
Rename to Vincent Adultman
ditman Feb 14, 2023
34704e6
_isJsSdkLoaded -> _jsSdkLoadedFuture
ditman Feb 14, 2023
908beac
Remove idToken comment.
ditman Feb 14, 2023
7087d49
Link issue to split mocking better.
ditman Feb 14, 2023
382ed3d
Remove dependency in package:jwt_decoder
ditman Feb 14, 2023
7d91c22
Remove unneeded cast call.
ditman Feb 16, 2023
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
5 changes: 4 additions & 1 deletion packages/google_sign_in/google_sign_in_web/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
## NEXT
## 0.11.0

* **Breaking Change:** Migrates JS-interop to `package:google_identity_services_web`
* Uses the new Google Identity Authentication and Authorization JS SDKs. [Docs](https://developers.google.com/identity).
* Added "Migrating to v0.11" section to the `README.md`.
* Updates minimum Flutter version to 3.0.

## 0.10.2+1
Expand Down
158 changes: 124 additions & 34 deletions packages/google_sign_in/google_sign_in_web/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,122 @@

The web implementation of [google_sign_in](https://pub.dev/packages/google_sign_in)

## Migrating to v0.11 (Google Identity Services)

The `google_sign_in_web` plugin is backed by the new Google Identity Services
(GIS) JS SDK since version 0.11.0.

The GIS SDK is used both for [Authentication](https://developers.google.com/identity/gsi/web/guides/overview)
and [Authorization](https://developers.google.com/identity/oauth2/web/guides/overview) flows.

The GIS SDK, however, doesn't behave exactly like the one being deprecated.
Some concepts have experienced pretty drastic changes, and that's why this
plugin required a major version update.

### Differences between Google Identity Services SDK and Google Sign-In for Web SDK.

The **Google Sign-In JavaScript for Web JS SDK** is set to be deprecated after
March 31, 2023. **Google Identity Services (GIS) SDK** is the new solution to
quickly and easily sign users into your app suing their Google accounts.

* In the GIS SDK, Authentication and Authorization are now two separate concerns.
* Authentication (information about the current user) flows will not
authorize `scopes` anymore.
* Authorization (permissions for the app to access certain user information)
flows will not return authentication information.
* The GIS SDK no longer has direct access to previously-seen users upon initialization.
* `signInSilently` now displays the One Tap UX for web.
* The GIS SDK only provides an `idToken` (JWT-encoded info) when the user
successfully completes an authentication flow. In the plugin: `signInSilently`.
* The plugin `signIn` method uses the Oauth "Implicit Flow" to Authorize the requested `scopes`.
* If the user hasn't `signInSilently`, they'll have to sign in as a first step
of the Authorization popup flow.
* If `signInSilently` was unsuccessful, the plugin will add extra `scopes` to
`signIn` and retrieve basic Profile information from the People API via a
REST call immediately after a successful authorization. In this case, the
`idToken` field of the `GoogleSignInUserData` will always be null.
* The GIS SDK no longer handles sign-in state and user sessions, it only provides
Authentication credentials for the moment the user did authenticate.
* The GIS SDK no longer is able to renew Authorization sessions on the web.
Once the token expires, API requests will begin to fail with unauthorized,
and user Authorization is required again.

See more differences in the following migration guides:

* Authentication > [Migrating from Google Sign-In](https://developers.google.com/identity/gsi/web/guides/migration)
* Authorization > [Migrate to Google Identity Services](https://developers.google.com/identity/oauth2/web/guides/migration-to-gis)

### New use cases to take into account in your app

#### Enable access to the People API for your GCP project

Since the GIS SDK is separating Authentication from Authorization, the
[Oauth Implicit pop-up flow](https://developers.google.com/identity/oauth2/web/guides/use-token-model)
used to Authorize scopes does **not** return any Authentication information
anymore (user credential / `idToken`).

If the plugin is not able to Authenticate an user from `signInSilently` (the
OneTap UX flow), it'll add extra `scopes` to those requested by the programmer
so it can perform a [People API request](https://developers.google.com/people/api/rest/v1/people/get)
to retrieve basic profile information about the user that is signed-in.

The information retrieved from the People API is used to complete data for the
[`GoogleSignInAccount`](https://pub.dev/documentation/google_sign_in/latest/google_sign_in/GoogleSignInAccount-class.html)
object that is returned after `signIn` completes successfully.

#### `signInSilently` always returns `null`

Previous versions of this plugin were able to return a `GoogleSignInAccount`
object that was fully populated (signed-in and authorized) from `signInSilently`
because the former SDK equated "is authenticated" and "is authorized".

With the GIS SDK, `signInSilently` only deals with user Authentication, so users
retrieved "silently" will only contain an `idToken`, but not an `accessToken`.

Only after `signIn` or `requestScopes`, a user will be fully formed.

The GIS-backed plugin always returns `null` from `signInSilently`, to force apps
that expect the former logic to perform a full `signIn`, which will result in a
fully Authenticated and Authorized user, and making this migration easier.

#### `idToken` is `null` in the `GoogleSignInAccount` object after `signIn`

Since the GIS SDK is separating Authentication and Authorization, when a user
fails to Authenticate through `signInSilently` and the plugin performs the
fallback request to the People API described above,
the returned `GoogleSignInUserData` object will contain basic profile information
(name, email, photo, ID), but its `idToken` will be `null`.

This is because JWT are cryptographically signed by Google Identity Services, and
this plugin won't spoof that signature when it retrieves the information from a
simple REST request.

#### User Sessions

Since the GIS SDK does _not_ manage user sessions anymore, apps that relied on
this feature might break.

If long-lived sessions are required, consider using some user authentication
system that supports Google Sign In as a federated Authentication provider,
like [Firebase Auth](https://firebase.google.com/docs/auth/flutter/federated-auth#google),
or similar.

#### Expired / Invalid Authorization Tokens

Since the GIS SDK does _not_ auto-renew authorization tokens anymore, it's now
the responsibility of your app to do so.

Apps now need to monitor the status code of their REST API requests for response
codes different to `200`. For example:

* `401`: Missing or invalid access token.
* `403`: Expired access token.

In either case, your app needs to prompt the end user to `signIn` or
`requestScopes`, to interactively renew the token.

The GIS SDK limits authorization token duration to one hour (3600 seconds).

## Usage

### Import the package
Expand All @@ -12,7 +128,7 @@ normally. This package will be automatically included in your app when you do.

### Web integration

First, go through the instructions [here](https://developers.google.com/identity/sign-in/web/sign-in#before_you_begin) to create your Google Sign-In OAuth client ID.
First, go through the instructions [here](https://developers.google.com/identity/gsi/web/guides/get-google-api-clientid) to create your Google Sign-In OAuth client ID.

On your `web/index.html` file, add the following `meta` tag, somewhere in the
`head` of the document:
Expand All @@ -29,7 +145,10 @@ You can do this by:
2. Clicking "Edit" in the OAuth 2.0 Web application client that you created above.
3. Adding the URIs you want to the **Authorized JavaScript origins**.

For local development, may add a `localhost` entry, for example: `http://localhost:7357`
For local development, you must add two `localhost` entries:

* `http://localhost` and
* `http://localhost:7357` (or any port that is free in your machine)

#### Starting flutter in http://localhost:7357

Expand All @@ -45,48 +164,19 @@ flutter run -d chrome --web-hostname localhost --web-port 7357

Read the rest of the instructions if you need to add extra APIs (like Google People API).


### Using the plugin
Add the following import to your Dart code:

```dart
import 'package:google_sign_in/google_sign_in.dart';
```

Initialize GoogleSignIn with the scopes you want:

```dart
GoogleSignIn _googleSignIn = GoogleSignIn(
scopes: [
'email',
'https://www.googleapis.com/auth/contacts.readonly',
],
);
```

[Full list of available scopes](https://developers.google.com/identity/protocols/googlescopes).

Note that the `serverClientId` parameter of the `GoogleSignIn` constructor is not supported on Web.
See the [**Usage** instructions of `package:google_sign_in`](https://pub.dev/packages/google_sign_in#usage)

You can now use the `GoogleSignIn` class to authenticate in your Dart code, e.g.

```dart
Future<void> _handleSignIn() async {
try {
await _googleSignIn.signIn();
} catch (error) {
print(error);
}
}
```
Note that the **`serverClientId` parameter of the `GoogleSignIn` constructor is not supported on Web.**

## Example

Find the example wiring in the [Google sign-in example application](https://github.com/flutter/plugins/blob/main/packages/google_sign_in/google_sign_in/example/lib/main.dart).

## API details

See the [google_sign_in.dart](https://github.com/flutter/plugins/blob/main/packages/google_sign_in/google_sign_in/lib/google_sign_in.dart) for more API details.
See [google_sign_in.dart](https://github.com/flutter/plugins/blob/main/packages/google_sign_in/google_sign_in/lib/google_sign_in.dart) for more API details.

## Contributions and Testing

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
targets:
$default:
sources:
- integration_test/*.dart
- lib/$lib$
- $package$
Loading