Flutter web でFirebase＆GoogleSignIn認証しようとしてハマった話（2.8以降は注意？）

Flutterでwebアプリ開発を始めました。
以前にVue.jsを使ってFirebaseHostingを使ったWebアプリでFirebase＆GoogleSignInでの認証を作っていて、「認証に簡単にできるんだ！」と感動した覚えがあったので、今回もサクッと認証機能を入れ込もうと思ったのですが、、、、思いの他はまったので、記録として残します。

## 最初に結論

- Flutter2.8以降でFirebaseを使ったログイン方法が変わっているようです。（詳しくは理解していない）
- このバージョン以前の実装方法はいろんな記事があり、そのまま実装で大丈夫そう。
- 2.8以降？ではFirebaseAuth.signInWithPopup()を使うとうまくいく。（行った）

### 補足
- この記事ではFirebaseの設定や、GCPの設定は記載していません。他参考サイトを貼っておきます。
- 環境・パッケージのバージョンは最後に記載しています。

## はまったコード
だいたい色んな参考サイトを見てみるとこんな感じで記載されていると思います。
Flutterを使ったAndroidアプリ、iOSアプリならこれで大丈夫な様子。
```Dart:
  Future<void> googleSignin() async {
    // Google認証の部分
    final GoogleSignIn _googleSignIn = GoogleSignIn(
      scopes: [
        'email',
        'https://www.googleapis.com/auth/contacts.readonly',
      ],
    );
    try {
      final GoogleSignInAccount? googleUser = await _google_signin.signIn();
    } catch (error) { print(error); }
    
    final GoogleSignInAuthentication? googleAuth =
        await googleUser?.authentication;

    // 🔥🔥🔥🔥🔥 クレデンシャルの取得 🔥🔥🔥🔥🔥
    final AuthCredential credential = GoogleAuthProvider.credential(
      idToken: googleAuth?.idToken,
      accessToken: googleAuth?.accessToken,
    );

    // 　Firebase 認証　インスタンス生成
    final FirebaseAuth _fauth = FirebaseAuth.instance;
    // Google認証を通過した後、Firebase側にログイン　
    try {
      final UserCredential result =
          await _fauth.signInWithCredential(credential);
      user = result.user;
    
    // TODO:ログイン後画面にアカウントを引き継ぐ
    // ログイン後の画面遷移
      Navigator.push(
          context,
          MaterialPageRoute(
            builder: (context) => NextView(), 
          ));
    } catch (e) {
      print(e);
    }
  }

```
このコードで散々試しましたが、、、🔥🔥🔥🔥🔥の部分で以下のエラーが出て、うまくいきませんでした。。。

```:はまったエラー
Error: Assertion failed:
file:///xxxx/flutter_dev/flutter/.pub-cache/hosted/pub.dartlang.org
/firebase_auth_platform_interface-6.2.5/lib/src/providers/google_auth.dart:43
:12
accessToken != null || idToken != null
"At least one of ID token and access token is required"
    at Object.throw_ [as throw] (http://localhost:7357/dart_sdk.js:5067:11)
    at Object.assertFailed (http://localhost:7357/dart_sdk.js:4992:15)
    at Function.credential
    (http://localhost:7357/packages/firebase_auth_platform_interface/src/type
    s.dart.lib.js:516:59)
    at main.xxxx.new.googleSignin
    (http://localhost:7357/packages/mappy/main.dart.lib.js:527:57)
    at googleSignin.next (<anonymous>)
    at http://localhost:7357/dart_sdk.js:40571:33
    at _RootZone.runUnary (http://localhost:7357/dart_sdk.js:40441:59)
    at _FutureListener.thenAwait.handleValue
    (http://localhost:7357/dart_sdk.js:35363:29)
    at handleValueCallback (http://localhost:7357/dart_sdk.js:35931:49)
    at Function._propagateToListeners
    (http://localhost:7357/dart_sdk.js:35969:17)
    at _Future.new.[_complete] (http://localhost:7357/dart_sdk.js:35809:25)
    at http://localhost:7357/dart_sdk.js:34915:30
    at internalCallback (http://localhost:7357/dart_sdk.js:26619:11)
```
なぜかはよくわかりませんでしたが、googleUser?.authenticationの結果は取得できているものの、
それを使った、GoogleAuthProvider.credential(xx)の結果はnullになっている。。。

## うまく動いたコード
ちょーシンプルですが、いかでGoogle認証して、Firebase認証までしてくれます。
```Dart:
  Future<void> googleSignin() async {
    GoogleAuthProvider authProvider = GoogleAuthProvider();
    try {
      final UserCredential userCredential =
          await _fauth.signInWithPopup(authProvider);

      user = userCredential.user;
    // TODO:ログイン後画面にアカウントを引き継ぐ
    // ログイン後の画面遷移
      Navigator.push(
          context,
          MaterialPageRoute(
            builder: (context) => NextView(), 
          ));
    } catch (e) {
      print(e);
    }
```


## その他にハマった対策メモ
#### ローカルテストでGoogle認証を使うには、ポートを指定して起動する必要がある
ポート指定での起動方法
```
$ flutter run -d chrome --web-hostname localhost --web-port 7357
```
「GCP -> APIとサービス　-> 認証情報」で以下のように設定してあげる。
![ウェブ_アプリケーション_のクライアント_ID_–_API_とサービス_–_kenymap2022_–_Google_Cloud_Platform.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/409199/87d92f01-c19b-8bfd-0083-9eee8072e90d.png)

#### 認証のリダイレクト先にFirebaseの登録が必要
同じく、「GCP -> APIとサービス　-> 認証情報」で以下のように設定してあげる。
![ウェブ_アプリケーション_のクライアント_ID_–_API_とサービス_–_kenymap2022_–_Google_Cloud_Platform.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/409199/060415dc-4aa1-c23a-66c1-e0858c5e5b1a.png)
この部分に下のID部分を登録してあげる。
![Banners_and_Alerts_と_kenymap2022_-_プロジェクトの設定_-_Firebase_コンソール.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/409199/70df0830-fa45-44d8-6ecd-22ffc2984ea1.png)

# 参考サイト
- [FlutterへFirebase AuthenticationとGoogle Sign-Inで簡単にログイン機能を実装](https://zenn.dev/welchi/articles/firebase-auth)
Firebaseの設定など含めて基本的なことがわかりやすく解説されています。

- [Flutterを使ったGoogleサインイン＆Firebase認証](https://blog.codemagic.io/firebase-authentication-google-sign-in-using-flutter-jpn/)
解決につながったサイト

# 環境

### doctor
```
$ flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 2.10.3, on Mac OS X 10.14.6 18G103 darwin-x64, locale ja-JP)
[✗] Android toolchain - develop for Android devices
    ✗ Unable to locate Android SDK.
      Install Android Studio from: https://developer.android.com/studio/index.html
      On first launch it will assist you in installing the Android SDK components.
      (or visit https://flutter.dev/docs/get-started/install/macos#android-setup for detailed instructions).
      If the Android SDK has been installed to a custom location, please use
      `flutter config --android-sdk` to update to that location.

[✗] Xcode - develop for iOS and macOS
    ✗ Xcode installation is incomplete; a full installation is necessary for iOS development.
      Download at: https://developer.apple.com/xcode/download/
      Or install Xcode via the App Store.
      Once installed, run:
        sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer
        sudo xcodebuild -runFirstLaunch
    ✗ CocoaPods not installed.
        CocoaPods is used to retrieve the iOS and macOS platform side's plugin code that responds to your plugin usage on the
        Dart side.
        Without CocoaPods, plugins will not work on iOS or macOS.
        For more info, see https://flutter.dev/platform-plugins
      To install see https://guides.cocoapods.org/using/getting-started.html#installation for instructions.
[✓] Chrome - develop for the web
[!] Android Studio (not installed)
[✓] VS Code (version 1.66.2)
[✓] Connected device (1 available)
[✓] HTTP Host Availability

! Doctor found issues in 3 categories.
```

### パッケージバージョン
```
$ flutter pub outdated
Showing outdated packages.
[*] indicates versions that are not the latest available.

Package Name              Current  Upgradable  Resolvable  Latest  

direct dependencies: all up-to-date.

dev_dependencies:        
firebase_core             *1.15.0  1.16.0      1.16.0      1.16.0  
flutter_lints             *1.0.4   *1.0.4      *1.0.4      2.0.1   
google_maps_flutter       *2.1.3   2.1.4       2.1.4       2.1.4   

transitive dependencies: 
characters                *1.2.0   *1.2.0      *1.2.0      1.2.1   
collection                *1.15.0  *1.15.0     *1.15.0     1.16.0  
material_color_utilities  *0.1.3   *0.1.3      *0.1.3      0.1.5   
vector_math               *2.1.1   *2.1.1      *2.1.1      2.1.2   

transitive dev_dependencies:
async                     *2.8.2   *2.8.2      *2.8.2      2.9.0   
fake_async                *1.2.0   *1.2.0      *1.2.0      1.3.0   
google_maps               *5.3.0   *5.3.0      *5.3.0      6.1.0   
js                        *0.6.3   *0.6.3      *0.6.3      0.6.4   
lints                     *1.0.1   *1.0.1      *1.0.1      2.0.0   
path                      *1.8.0   *1.8.0      *1.8.0      1.8.1   
source_span               *1.8.1   *1.8.1      *1.8.1      1.9.0   
test_api                  *0.4.8   *0.4.8      *0.4.8      0.4.9   

2 upgradable dependencies are locked (in pubspec.lock) to older versions.
To update these dependencies, use `flutter pub upgrade`.
```