🐈

【Flutter】Firebase Auth パスワード認証でUIDを指定してユーザーを作成する

2024/01/02に公開

Firebase AuthでEmail/パスワードで認証すると、自動でUIDが割り当てられます。UIDはランダムで発行されるものですが、自分で指定したい。なかなかニッチなニーズとは思いますが、その方法を紹介します。(UIDは以下の赤矢印の値)

結論

UIDを後から変更することは難しいため、
https://stackoverflow.com/a/59203323
以下の手順を踏んで特定のUIDのユーザーを作成します。

カスタムトークンでログイン

メールリンク認証

パスワードセット

アプリ側はFlutter, サーバーサイドはGoのコード例で説明していきます。

手順

1. カスタムトークンを作成

早速ですが、アプリ側でカスタムトークンを発行することはできないので、サーバーサイドなどでFirebase Admin SDKを使用して発行します。カスタムトークンの有効期限は1時間です。

token, err := client.CustomToken(ctx, "指定したいUID")
if err != nil {
	log.Fatalf("error minting custom token: %v\n", err)
}

https://firebase.google.com/docs/auth/admin/create-custom-tokens?hl=ja#create_custom_tokens_using_the_firebase_admin_sdk

2. カスタムトークンでログインする

1.で発行したカスタムトークンをつかってアプリでログインします。

FirebaseAuth.instance.signInWithCustomToken(token);

https://firebase.google.com/docs/auth/flutter/custom-auth?hl=ja#authenticate_with_firebase

3. メール認証

2.までの状態だと、Email/パスワードが紐づいていない状態になります。
(一番左がハイフン(-)になっている)

ここからメールリンク認証をすることでメールを紐付けます。

    var acs = ActionCodeSettings(
      // The link will redirect the user to this URL if the app is not
      // installed on their device and the app was not able to be installed.
      url: url,
      handleCodeInApp: true,
      iOSBundleId: "iOSのBundleIdentifier",
      androidPackageName: "Androidのパッケージ名",
      androidInstallApp: true,
      androidMinimumVersion: '24',
    );

    try {
      await FirebaseAuth.instance
          .sendSignInLinkToEmail(email: email, actionCodeSettings: acs);
    } on FirebaseAuthException catch (e) {
      log('Error sending email verification $e');
      return;
    }

    // Store mail to shared preferences
    SharedPreferences.getInstance().setString("temp_email", email);

https://firebase.google.com/docs/auth/flutter/email-link-auth?hl=ja#send_an_authentication_link_to_the_users_email_address
上記で飛んだメールを踏んでアプリが起動したら、認証します。
Dynamic Link(サービス終了予定なので、他の方法を調べたらまた記事にします・・・)を使う前提です。

    FirebaseDynamicLinks.instance.onLink.listen((dynamicLinkData) {
      handle(data: dynamicLinkData);
    }).onError((error) {
      // Handle errors
    });
    
    Future<void> handle({
      required PendingDynamicLinkData data,
    }) async {
      final auth = FirebaseAuth.instance;
      final emailLink = data.link.toString();
      final emailAuth = await SharedPreferences.getInstance().getString("temp_email");
      if (emailAuth != null && auth.isSignInWithEmailLink(emailLink)) {
        final authCredential = EmailAuthProvider.credentialWithLink(
          email: emailAuth,
          emailLink: emailLink.toString(),
        );
        try {
          await auth.currentUser?.linkWithCredential(authCredential);
        } catch (e, s) {
          log(e.toString(), stackTrace: s);
        }
      }
    }

https://firebase.google.com/docs/auth/flutter/email-link-auth?hl=ja#linkingre-authentication_with_email_link

4. パスワードセット

最後にパスワードをセットします。

FirebaseAuth.instance.currentUser?.updatePassword("newPassword")

これで指定のUIDでEmail/パスワード認証ユーザーの作成を再現できました。

Discussion