Google I/O 2022 で発表された Firebase の最新情報をご覧ください。詳細

メールリンクを使用してFirebaseで認証する

コレクションでコンテンツを整理 必要に応じて、コンテンツの保存と分類を行います。

Firebase Authenticationを使用して、ユーザーがクリックしてサインインできるリンクを含むメールを送信することで、ユーザーにログインできます。その過程で、ユーザーのメールアドレスも確認されます。

電子メールでサインインすることには多くの利点があります。

  • 低摩擦のサインアップとサインイン。
  • アプリケーション間でのパスワードの再利用のリスクが低くなります。これにより、適切に選択されたパスワードのセキュリティが損なわれる可能性があります。
  • ユーザーが電子メールアドレスの正当な所有者であることを確認しながら、ユーザーを認証する機能。
  • ユーザーは、アクセス可能な電子メールアカウントのみでサインインできます。電話番号やソーシャルメディアアカウントの所有権は必要ありません。
  • ユーザーは、モバイルデバイスでは面倒なパスワードを入力(または覚えて)することなく、安全にサインインできます。
  • 以前に電子メール識別子(パスワードまたはフェデレーション)でサインインした既存のユーザーは、電子メールだけでサインインするようにアップグレードできます。たとえば、パスワードを忘れたユーザーは、パスワードをリセットしなくてもサインインできます。

あなたが始める前に

  1. まだ行っていない場合は、スタートガイドの手順に従ってください。

  2. FirebaseプロジェクトでEメールリンクのサインインを有効にします。

    メールリンクでユーザーにログインするには、まずFirebaseプロジェクトでメールプロバイダーとメールリンクのログイン方法を有効にする必要があります。

    1. Firebaseコンソールで、[認証]セクションを開きます。
    2. [サインイン方法]タブで、電子メール/パスワードプロバイダーを有効にします。電子メールリンクサインインを使用するには、電子メール/パスワードサインインを有効にする必要があることに注意してください。
    3. 同じセクションで、 Eメールリンク(パスワードなしのサインイン)サインイン方法を有効にします。
    4. [保存]をクリックします。

認証フローを開始するには、ユーザーにメールアドレスの入力を求めるインターフェースを提示してから、 sendSignInLinkToEmail()を呼び出して、Firebaseがユーザーのメールに認証リンクを送信するようにリクエストします。

  1. ActionCodeSettingsオブジェクトを作成します。これにより、Firebaseにメールリンクの作成方法に関する手順が提供されます。次のフィールドを設定します。

    • url :埋め込みへのディープリンクと渡される追加の状態。リンクのドメインは、Firebase Consoleの承認済みドメインのリストにホワイトリストに登録する必要があります。このリストは、[サインイン方法]タブ([認証]-> [サインイン方法])に移動して見つけることができます。アプリがデバイスにインストールされておらず、アプリをインストールできなかった場合、リンクはユーザーをこのURLにリダイレクトします。

    • androidPackageNameおよびIOSBundleId :サインインリンクがAndroidまたはiOSデバイスで開かれるときに使用するアプリ。モバイルアプリを介してメールアクションリンクを開くようにFirebaseDynamicLinksを設定する方法の詳細をご覧ください。

    • handleCodeInApptrueに設定します。サインイン操作は、他の帯域外の電子メールアクション(パスワードのリセットと電子メールの検証)とは異なり、常にアプリで完了する必要があります。これは、フローの最後に、ユーザーがサインインし、ユーザーの認証状態がアプリ内で保持されることが期待されるためです。

    • dynamicLinkDomain :プロジェクトに複数のカスタム動的リンクドメインが定義されている場合、指定されたモバイルアプリ(たとえば、 example.page.link )を介してリンクを開くときに使用するドメインを指定します。それ以外の場合は、最初のドメインが自動的に選択されます。

    var acs = ActionCodeSettings(
        // URL you want to redirect back to. The domain (www.example.com) for this
        // URL must be whitelisted in the Firebase Console.
        url: 'https://www.example.com/finishSignUp?cartId=1234',
        // This must be true
        handleCodeInApp: true,
        iOSBundleId: 'com.example.ios',
        androidPackageName: 'com.example.android',
        // installIfNotAvailable
        androidInstallApp: true,
        // minimumVersion
        androidMinimumVersion: '12');
    
  2. ユーザーにメールアドレスを尋ねます。

  3. ユーザーの電子メールへの認証リンクを送信し、ユーザーが同じデバイスで電子メールのサインインを完了した場合に備えて、ユーザーの電子メールを保存します。

    var emailAuth = 'someemail@domain.com';
    FirebaseAuth.instance.sendSignInLinkToEmail(
            email: emailAuth, actionCodeSettings: acs)
        .catchError((onError) => print('Error sending email verification $onError'))
        .then((value) => print('Successfully sent email verification'));
    });
    

セキュリティ上の懸念

サインインリンクが意図しないユーザーとして、または意図しないデバイスでサインインするために使用されないようにするために、Firebase Authでは、サインインフローの完了時にユーザーのメールアドレスを指定する必要があります。サインインを成功させるには、この電子メールアドレスがサインインリンクが最初に送信されたアドレスと一致している必要があります。

サインイン電子メールを送信するときに、たとえばSharedPreferencesを使用して電子メールアドレスをローカルに保存することにより、リンクを要求するのと同じデバイスでサインインリンクを開くユーザーのこのフローを合理化できます。次に、このアドレスを使用してフローを完了します。リダイレクトURLパラメータでユーザーの電子メールを渡さないでください。再利用すると、セッションインジェクションが有効になる可能性があります。

サインインの完了後、以前の未確認のサインインメカニズムはユーザーから削除され、既存のセッションは無効になります。たとえば、誰かが以前に同じメールアドレスとパスワードで未確認のアカウントを作成した場合、所有権を主張してその未確認のアカウントを作成したなりすまし者が未確認のメールアドレスとパスワードで再度ログインするのを防ぐために、ユーザーのパスワードが削除されます。

また、リンクが中間サーバーによって傍受される可能性を回避するために、本番環境ではHTTPSURLを使用するようにしてください。

Firebase認証では、FirebaseDynamicLinksを使用してメールリンクをモバイルデバイスに送信します。モバイルアプリケーションを介してサインインを完了するには、着信アプリケーションリンクを検出し、基になるディープリンクを解析してから、サインインを完了するようにアプリケーションを構成する必要があります。

  1. ガイドのFlutterでダイナミックリンクを受信するようにアプリを設定します。

  2. リンクハンドラーで、リンクが電子メールリンク認証用であるかどうかを確認し、使用する場合は、サインインプロセスを完了します。

    // Confirm the link is a sign-in with email link.
    if (FirebaseAuth.instance.isSignInWithEmailLink(emailLink)) {
      try {
        // The client SDK will parse the code from the link for you.
        final userCredential = await FirebaseAuth.instance
            .signInWithEmailLink(email: emailAuth, emailLink: emailLink);
    
        // You can access the new user via userCredential.user.
        final emailAddress = userCredential.user?.email;
    
        print('Successfully signed in with email link!');
      } catch (error) {
        print('Error signing in with email link.');
      }
    }
    

この認証方法を既存のユーザーにリンクすることもできます。たとえば、電話番号など、以前に別のプロバイダーで認証されたユーザーは、このサインイン方法を既存のアカウントに追加できます。

違いは、操作の後半にあります。

final authCredential = EmailAuthProvider
    .credentialWithLink(email: emailAuth, emailLink: emailLink.toString());
try {
    await FirebaseAuth.instance.currentUser
        ?.linkWithCredential(authCredential);
} catch (error) {
    print("Error linking emailLink credential.");
}

これは、機密性の高い操作を実行する前に、電子メールリンクユーザーを再認証するためにも使用できます。

final authCredential = EmailAuthProvider
    .credentialWithLink(email: emailAuth, emailLink: emailLink.toString());
try {
    await FirebaseAuth.instance.currentUser
        ?.reauthenticateWithCredential(authCredential);
} catch (error) {
    print("Error reauthenticating credential.");
}

ただし、元のユーザーがログインしていない別のデバイスでフローが終了する可能性があるため、このフローは完了しない可能性があります。その場合、ユーザーにエラーを表示して、同じデバイスでリンクを開くように強制することができます。リンクでいくつかの状態を渡して、操作のタイプとユーザーuidに関する情報を提供できます。

電子メールによるパスワードとリンクベースのサインインの両方をサポートしている場合、パスワード/リンクユーザーのサインイン方法を区別するには、 fetchSignInMethodsForEmailを使用します。これは、ユーザーが最初に電子メールを提供するように求められ、次にサインインの方法が提示される識別子優先フローに役立ちます。

try {
    final signInMethods =
        await FirebaseAuth.instance.fetchSignInMethodsForEmail(emailAuth);
    final userExists = signInMethods.isNotEmpty;
    final canSignInWithLink = signInMethods
        .contains(EmailAuthProvider.EMAIL_LINK_SIGN_IN_METHOD);
    final canSignInWithPassword = signInMethods
        .contains(EmailAuthProvider.EMAIL_PASSWORD_SIGN_IN_METHOD);
} on FirebaseAuthException catch (exception) {
    switch (exception.code) {
        case "invalid-email":
            print("Not a valid email address.");
            break;
        default:
            print("Unknown error.");
    }
}

上記のように、email/passwordとemail/linkは、サインインの方法が異なる同じEmailAuthProvider (同じPROVIDER_ID )と見なされます。

次のステップ

ユーザーが新しいアカウントを作成すると、このアカウントはFirebaseプロジェクトの一部として保存され、ユーザーが使用したログイン方法に関係なく、プロジェクト内のすべてのアプリでユーザーを識別するために使用できます。

アプリでは、 Userオブジェクトからユーザーの基本的なプロファイル情報を取得できます。ユーザーの管理を参照してください。

Firebase RealtimeDatabaseとCloudStorageのセキュリティルールでは、ログインしたユーザーの一意のユーザーIDをauth変数から取得し、それを使用してユーザーがアクセスできるデータを制御できます。

認証プロバイダーのクレデンシャルを既存のユーザーアカウントにリンクすることで、ユーザーが複数の認証プロバイダーを使用してアプリにサインインできるようにすることができます。

ユーザーをサインアウトするには、 signOut()を呼び出します。

await FirebaseAuth.instance.signOut();