🍀

[Flutter]LINEログイン連携でlinkWithCredentialがうまくいかない

2024/03/13に公開

やりたいこと

すでにFirebaseAuthでメール認証したアカウントでLINEログイン連携をしてLINEのアカウントを連携したい

苦戦した理由

LINEアカウントでのサインインはsignInWithCustomTokenを利用する記事がたくさん出てくるが、linkWithCredentialのパターンの事例がなくてハマった。

うまくいかなかったコード①

import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter_line_sdk/flutter_line_sdk.dart';

...

final loginOption = LoginOption(false, 'normal');
final result = await LineSDK.instance.login(
  scopes: ['profile', 'openid', 'email'],
  option: loginOption,
);

final provider = OAuthProvider('oidc.line');
final credential = provider.credential(
  accessToken: result.accessToken.value,
);

await _firebaseAuth.currentUser!.linkWithCredential(credential);

エラーの内容

LINEログイン後に入手できるアクセストークンを用いてcredentialを作ってみたが、エラーになった。エラーの内容が汎用的すぎて解決策が掴めず...

https://github.com/firebase/flutterfire/issues/7453

うまくいかなかったコード②

もしかしたらアクセストークンでcredentialを作るのが何か噛み合ってないのではと思い、idTokenの方でcredentialを作るのを試みた。

import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter_line_sdk/flutter_line_sdk.dart';
import 'package:nonce/nonce.dart';

...

final nonce = Nonce.generate();
final loginOption = LoginOption(false, 'normal')..idTokenNonce = nonce;
final result = await LineSDK.instance.login(
  scopes: ['profile', 'openid', 'email'],
  option: loginOption,
);

final provider = OAuthProvider('oidc.line');
final credential = provider.credential(
  idToken: result.accessToken.idTokenRaw,
  rawNonce: nonce,
);

await _firebaseAuth.currentUser!.linkWithCredential(credential);

エラーの内容

同じ現象にハマってる人がいた。

https://github.com/firebase/flutterfire/discussions/10296

うまくいったコード

上のうまくいかなかったコード②を元にnonceをSHA256で生成すればいけるのではと思い、LineSDKでログインするときに使うNonceをSHA256にして、credentialではrawNonceなので、元々のNonce.generate()で生成した値を利用するとうまくいった。

import 'dart:convert';
import 'package:crypto/crypto.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter_line_sdk/flutter_line_sdk.dart';
import 'package:nonce/nonce.dart';

...

final nonce = Nonce.generate();
final digest = sha256.convert(utf8.encode(nonce));
final sha256Nonce = digest.toString();
final loginOption = LoginOption(false, 'normal')..idTokenNonce = sha256Nonce;
final result = await LineSDK.instance.login(
  scopes: ['profile', 'openid', 'email'],
  option: loginOption,
);

final provider = OAuthProvider('oidc.line');
final credential = provider.credential(
  idToken: result.accessToken.idTokenRaw,
  rawNonce: nonce,
);

await _firebaseAuth.currentUser!.linkWithCredential(credential);

Discussion