概要
たいしたことではないのですが、開発中にfirebase authのGoogle SSOができない!というので数日悩んだので色々残しておきます。今回はソースコードのみ。環境準備の部分はやる気が出たら書きます
構成としてはクライアントがflutter, バックエンドにnest.jsという構成です
google_sign_in v7使用の記事です
以下のエラーがめちゃでてた
FirebaseAuthError: Firebase ID token has invalid signature. See https://firebase.google.com/docs/auth/admin/verify-id-tokens for details on how to retrieve an ID token.
まず、完成形のソースコード
Flutter側のGoogle SSOのソースコード
※以下のバージョン
firebase_core: ^4.2.0
firebase_auth: ^6.1.1
google_sign_in: ^7.2.0
import 'dart:io';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:google_sign_in/google_sign_in.dart';
Future<void> _signIn() async {
await _initializeGoogleSignIn();
try {
// 1.プラットフォームの認証機能対応の確認
if (!_googleSignIn.supportsAuthenticate()) {
throw Exception('Authenticate not supported on this platform');
}
// 2.googleサインイン
final googleUser = await _googleSignIn.authenticate();
final GoogleSignInAuthentication googleAuth = googleUser.authentication;
final credential = GoogleAuthProvider.credential(
idToken: googleAuth.idToken,
);
// 3.Firebase認証
final UserCredential userCredential = await FirebaseAuth.instance
.signInWithCredential(credential);
// 4.このidTokenを使用
final idToken = await userCredential.user!.getIdToken();
debugPrint('firebaseIdToken: ${idToken}');
} catch (e) {
print('Sign-in error: $e');
debugPrint("Error sign in google : $e");
}
}
Future<void> _initializeGoogleSignIn() async {
// Initialize and listen to authentication events
await _googleSignIn.initialize();
_googleSignIn.authenticationEvents.listen((event) {
setState(() {
debugPrint('認証後 リスナー');
_user = switch (event) {
GoogleSignInAuthenticationEventSignIn() => event.user,
GoogleSignInAuthenticationEventSignOut() => null,
};
_email = _user?.email;
});
});
}
Nest.js側のソースコード
import { getAuth } from 'firebase-admin/auth';
import { Injectable } from '@nestjs/common';
import { OAuth2Client } from 'google-auth-library';
@Injectable()
export class GoogleOidc {
constructor() { }
public async create(idToken: string): Promise<void> {
try {
const decodedToken = await getAuth().verifyIdToken(idToken);
// 2. 検証済みのPayload(ユーザー情報)を取得
const payload = decodedToken;
if (!payload) {
throw new Error('IDトークンのペイロードが取得できませんでした');
}
// payloadを使用して後続処理を進める
} catch (error) {
// 検証失敗!トークンの期限切れ、改ざん、Client ID不一致など
console.error('IDトークンの検証に失敗しました:', error);
throw new Error('認証に失敗しました。無効なIDトークンです。');
}
}
}
今回のしくじり
まだ開発中で、バックエンドのAPIをたたかずコンソールに出力したIDトークンをPostmanを使って送るという形で進めているところでした
超初歩のflutterのdebugPrintが文字数制限がありIDトークンの全文が出力されていないというミスでした。。
以下の記載がミス!!
debugPrint('firebaseIdToken: ${idToken}');
以下の形でないと正しく全文でない
if (idToken != null) {
const int chunkSize = 500; // 500文字で固定
int i = 0;
// トークンの長さ全体をループする
while (i < idToken.length) {
// 終点のインデックスを計算
// 現在のインデックス + チャンクサイズ と トークン全体の長さの小さい方
int endIndex = (i + chunkSize < idToken.length)
? (i + chunkSize)
: idToken.length;
// 💡 トークンを出力
debugPrint(idToken.substring(i, endIndex));
// 💡 次のチャンクの開始位置へ移動
i = endIndex;
}
}
以下を参照
https://github.com/flutter/flutter/issues/31635
google SSOの実装に当たり参考にしたサイト
https://github.com/flutter/packages/blob/main/packages/google_sign_in/google_sign_in/MIGRATION.md
https://levelup.gitconnected.com/google-sign-in-with-firebase-auth-in-flutter-e44af358f7b6