FirebaseUI でウェブアプリに簡単にログイン機能を追加する

FirebaseUI は Firebase Authentication SDK を基に作成されたライブラリで、アプリで使用するドロップイン UI フローを提供します。FirebaseUI には次の利点があります。

  • 複数プロバイダ対応 - メールとパスワードのログインフロー、メールリンク、電話認証、Google、Facebook、Twitter、GitHub によるログインに対応しています。
  • アカウントのリンク - ID プロバイダ間でユーザー アカウントを安全にリンクできます。
  • カスタマイズ - アプリの要件に合わせて FirebaseUI の CSS スタイルを変更できます。FirebaseUI はオープンソースであるため、必要に応じてプロジェクトをフォークしてカスタマイズすることもできます。
  • ワンタップ登録と自動ログイン - ワンタップ登録を使用した自動統合により、迅速なクロスデバイス ログインを実現します。
  • ローカライズされた UI - 国際化によって 40 以上の言語に対応しています。
  • 匿名ユーザーのアップグレード - ログイン / 登録による匿名ユーザーのアップグレード機能。詳細については、Upgrading anonymous users セクションをご覧ください。

始める前に

  1. ウェブ アプリケーションに Firebase Authentication を追加します。その際に、v9 互換(推奨)またはそれ以前の SDK(上のサイドバーを参照)を使用していることを確認します。

  2. 次のいずれかのオプションを使用して FirebaseUI を追加します。

    1. CDN

      ページの <head> タグの中、Firebase コンソールの初期化スニペットの下に、次のスクリプトと CSS ファイルを含めます。

      <script src="https://www.gstatic.com/firebasejs/ui/6.0.1/firebase-ui-auth.js"></script>
      <link type="text/css" rel="stylesheet" href="https://www.gstatic.com/firebasejs/ui/6.0.1/firebase-ui-auth.css" />
      
    2. npm モジュール

      次のコマンドを使用し、npm を通じて FirebaseUI とその依存関係をインストールします。

      $ npm install firebaseui --save
      

      ソースファイルの中で、次のモジュールに対して require を実行します。

      var firebase = require('firebase');
      var firebaseui = require('firebaseui');
    3. Bower コンポーネント

      次のコマンドを使用し、Bower を通じて FirebaseUI とその依存関係をインストールします。

      $ bower install firebaseui --save

      HTML の中に必要なファイルを含めます。HTTP サーバーが bower_components/ 内のファイルを提供する場合の例を以下に示します。

      <script src="bower_components/firebaseui/dist/firebaseui.js"></script>
      <link type="text/css" rel="stylesheet" href="bower_components/firebaseui/dist/firebaseui.css" />
      

FirebaseUI の初期化

SDK をインポートした後、Auth UI を初期化します。

// Initialize the FirebaseUI Widget using Firebase.
var ui = new firebaseui.auth.AuthUI(firebase.auth());

ログイン方法の設定

Firebase を使用してログインできるようにするには、サポートするログイン方法を事前に有効にして設定しておく必要があります。

メールアドレスとパスワード

  1. Firebase コンソールで [Authentication] セクションを開き、メールとパスワードによる認証を有効にします。

  2. FirebaseUI signInOptions のリストにメール プロバイダ ID を追加します。

    ui.start('#firebaseui-auth-container', {
      signInOptions: [
        firebase.auth.EmailAuthProvider.PROVIDER_ID
      ],
      // Other config options...
    });
  3. 省略可: ユーザーに表示名の入力を求めるように EmailAuthProvider を構成できます(デフォルトは true)。

    ui.start('#firebaseui-auth-container', {
      signInOptions: [
        {
          provider: firebase.auth.EmailAuthProvider.PROVIDER_ID,
          requireDisplayName: false
        }
      ]
    });
  1. Firebase コンソールで [Authentication] セクションを開きます。 [Sign-in method] タブで [メール / パスワード] を有効にします。メールリンク ログインを使用するには、メール / パスワードによるログインを有効にする必要があります。

  2. 同じセクションで、ログイン方法として [メールリンク(パスワードなしでログイン)] を有効にして、[保存] をクリックします。

  3. FirebaseUI signInOptions のリストにメールプロバイダ ID とメールリンク signInMethod を追加します。

    ui.start('#firebaseui-auth-container', {
      signInOptions: [
        {
          provider: firebase.auth.EmailAuthProvider.PROVIDER_ID,
          signInMethod: firebase.auth.EmailAuthProvider.EMAIL_LINK_SIGN_IN_METHOD
        }
      ],
      // Other config options...
    });
  4. ログイン UI を条件付きでレンダリングする場合(単一ページアプリに関連する場合)は、ui.isPendingRedirect() を使用して、URL がメールリンクを使用したログインに対応していて、ログインを完了するには UI をレンダリングする必要があるかどうかを検出します。

    // Is there an email link sign-in?
    if (ui.isPendingRedirect()) {
      ui.start('#firebaseui-auth-container', uiConfig);
    }
    // This can also be done via:
    if (firebase.auth().isSignInWithEmailLink(window.location.href)) {
      ui.start('#firebaseui-auth-container', uiConfig);
    }
  5. 省略可: ユーザーによるクロスデバイス ログインの完了を許可またはブロックするように、メールリンク ログイン用の EmailAuthProvider を構成できます。

    リンクを送信するときに使用する firebase.auth.ActionCodeSettings 構成を取得するには、オプションの emailLinkSignIn コールバックを定義します。こうすると、リンクの処理方法、カスタムのダイナミック リンク、ディープリンクの追加状態などを指定できるようになります。これらを指定しない場合は、現在の URL が使用され、ウェブのみのフローがトリガーされます。

    FirebaseUI-web のメールリンクによるログインは FirebaseUI-AndroidFirebaseUI-iOS と互換性があり、FirebaseUI-Android からフローを開始したユーザーは FirebaseUI-web でリンクを開き、ログインを完了できます。逆のフローについても同じことが言えます。

    ui.start('#firebaseui-auth-container', {
      signInOptions: [
        {
          provider: firebase.auth.EmailAuthProvider.PROVIDER_ID,
          signInMethod: firebase.auth.EmailAuthProvider.EMAIL_LINK_SIGN_IN_METHOD,
          // Allow the user the ability to complete sign-in cross device,
          // including the mobile apps specified in the ActionCodeSettings
          // object below.
          forceSameDevice: false,
          // Used to define the optional firebase.auth.ActionCodeSettings if
          // additional state needs to be passed along request and whether to open
          // the link in a mobile app if it is installed.
          emailLinkSignIn: function() {
            return {
              // Additional state showPromo=1234 can be retrieved from URL on
              // sign-in completion in signInSuccess callback by checking
              // window.location.href.
              url: 'https://www.example.com/completeSignIn?showPromo=1234',
              // Custom FDL domain.
              dynamicLinkDomain: 'example.page.link',
              // Always true for email link sign-in.
              handleCodeInApp: true,
              // Whether to handle link in iOS app if installed.
              iOS: {
                bundleId: 'com.example.ios'
              },
              // Whether to handle link in Android app if opened in an Android
              // device.
              android: {
                packageName: 'com.example.android',
                installApp: true,
                minimumVersion: '12'
              }
            };
          }
        }
      ]
    });

OAuth プロバイダ(Google、Facebook、Twitter、GitHub)

  1. Firebase コンソールで [Authentication] セクションを開き、指定した OAuth プロバイダのログインを有効にします。対応する OAuth クライアント ID とシークレットも指定します。

  2. また、[Authentication] セクションで、ログインページがレンダリングされるドメインが承認対象ドメインのリストに追加されていることも確認します。

  3. FirebaseUI signInOptions のリストに OAuth プロバイダ ID を追加します。

    ui.start('#firebaseui-auth-container', {
      signInOptions: [
        // List of OAuth providers supported.
        firebase.auth.GoogleAuthProvider.PROVIDER_ID,
        firebase.auth.FacebookAuthProvider.PROVIDER_ID,
        firebase.auth.TwitterAuthProvider.PROVIDER_ID,
        firebase.auth.GithubAuthProvider.PROVIDER_ID
      ],
      // Other config options...
    });
  4. 省略可: プロバイダごとにカスタム スコープまたはカスタム OAuth パラメータを指定するには、プロバイダ値だけを渡すのではなく、オブジェクトを渡します。

    ui.start('#firebaseui-auth-container', {
      signInOptions: [
        {
          provider: firebase.auth.GoogleAuthProvider.PROVIDER_ID,
          scopes: [
            'https://www.googleapis.com/auth/contacts.readonly'
          ],
          customParameters: {
            // Forces account selection even when one account
            // is available.
            prompt: 'select_account'
          }
        },
        {
          provider: firebase.auth.FacebookAuthProvider.PROVIDER_ID,
          scopes: [
            'public_profile',
            'email',
            'user_likes',
            'user_friends'
          ],
          customParameters: {
            // Forces password re-entry.
            auth_type: 'reauthenticate'
          }
        },
        firebase.auth.TwitterAuthProvider.PROVIDER_ID, // Twitter does not support scopes.
        firebase.auth.EmailAuthProvider.PROVIDER_ID // Other providers don't need to be given as object.
      ]
    });

電話番号

  1. Firebase コンソールで [Authentication] セクションを開き、電話番号ログインを有効にします。

  2. また、ログインページがレンダリングされるドメインが承認対象ドメインに追加されていることを確認します。

  3. FirebaseUI signInOptions のリストに電話番号プロバイダ ID を追加します。

    ui.start('#firebaseui-auth-container', {
      signInOptions: [
        firebase.auth.PhoneAuthProvider.PROVIDER_ID
      ],
      // Other config options...
    });
  4. 省略可: PhoneAuthProvider でカスタムの reCAPTCHA パラメータを使用して、reCAPTCHA の表示または非表示を構成できます(デフォルトは normal)。詳しくは reCAPTCHA API のドキュメントをご覧ください。

    電話番号の入力で選択されるデフォルトの国も設定できます。国コードの完全なリストについては、サポートされている国コードのリストをご覧ください。未指定の場合、電話番号の入力はデフォルトで米国(+1)になります。

    現時点でサポートされているオプションは次のとおりです。

    ui.start('#firebaseui-auth-container', {
      signInOptions: [
        {
          provider: firebase.auth.PhoneAuthProvider.PROVIDER_ID,
          recaptchaParameters: {
            type: 'image', // 'audio'
            size: 'normal', // 'invisible' or 'compact'
            badge: 'bottomleft' //' bottomright' or 'inline' applies to invisible.
          },
          defaultCountry: 'GB', // Set default country to the United Kingdom (+44).
          // For prefilling the national number, set defaultNationNumber.
          // This will only be observed if only phone Auth provider is used since
          // for multiple providers, the NASCAR screen will always render first
          // with a 'sign in with phone number' button.
          defaultNationalNumber: '1234567890',
          // You can also pass the full phone number string instead of the
          // 'defaultCountry' and 'defaultNationalNumber'. However, in this case,
          // the first country ID that matches the country code will be used to
          // populate the country selector. So for countries that share the same
          // country code, the selected country may not be the expected one.
          // In that case, pass the 'defaultCountry' instead to ensure the exact
          // country is selected. The 'defaultCountry' and 'defaultNationaNumber'
          // will always have higher priority than 'loginHint' which will be ignored
          // in their favor. In this case, the default country will be 'GB' even
          // though 'loginHint' specified the country code as '+1'.
          loginHint: '+11234567890'
        }
      ]
    });

ログイン

FirebaseUI のログインフローを開始するには、基盤となる Auth インスタンスを渡して FirebaseUI インスタンスを初期化します。

// Initialize the FirebaseUI Widget using Firebase.
var ui = new firebaseui.auth.AuthUI(firebase.auth());

FirebaseUI のログイン ウィジェットがレンダリングされる HTML 要素を定義します。

<!-- The surrounding HTML is left untouched by FirebaseUI.
     Your app may use that space for branding, controls and other customizations.-->
<h1>Welcome to My Awesome App</h1>
<div id="firebaseui-auth-container"></div>
<div id="loader">Loading...</div>

FirebaseUI の設定を指定します(サポートするプロバイダ、UI のカスタマイズ、成功時のコールバックなど)。

var uiConfig = {
  callbacks: {
    signInSuccessWithAuthResult: function(authResult, redirectUrl) {
      // User successfully signed in.
      // Return type determines whether we continue the redirect automatically
      // or whether we leave that to developer to handle.
      return true;
    },
    uiShown: function() {
      // The widget is rendered.
      // Hide the loader.
      document.getElementById('loader').style.display = 'none';
    }
  },
  // Will use popup for IDP Providers sign-in flow instead of the default, redirect.
  signInFlow: 'popup',
  signInSuccessUrl: '<url-to-redirect-to-on-success>',
  signInOptions: [
    // Leave the lines as is for the providers you want to offer your users.
    firebase.auth.GoogleAuthProvider.PROVIDER_ID,
    firebase.auth.FacebookAuthProvider.PROVIDER_ID,
    firebase.auth.TwitterAuthProvider.PROVIDER_ID,
    firebase.auth.GithubAuthProvider.PROVIDER_ID,
    firebase.auth.EmailAuthProvider.PROVIDER_ID,
    firebase.auth.PhoneAuthProvider.PROVIDER_ID
  ],
  // Terms of service url.
  tosUrl: '<your-tos-url>',
  // Privacy policy url.
  privacyPolicyUrl: '<your-privacy-policy-url>'
};

最後に、FirebaseUI Auth のインターフェースをレンダリングします。

// The start method will wait until the DOM is loaded.
ui.start('#firebaseui-auth-container', uiConfig);

匿名ユーザーのアップグレード

匿名ユーザーのアップグレードを有効にする

匿名ユーザーが永久アカウントにログインまたは登録する際、そのユーザーが登録前に行っていた操作を続行できるように設定できます。それには、ログイン UI を構成するときに autoUpgradeAnonymousUserstrue に設定します(このオプションはデフォルトでは無効になっています)。

匿名ユーザーのアップグレードの統合における競合の処理

最初に匿名でログインしたユーザーが、既存の Firebase ユーザーにアップグレードしようとするケースがあります。既存のユーザーを別の既存のユーザーにリンクすることはできないため、こうした試行が行われると、FirebaseUI はエラーコード firebaseui/anonymous-upgrade-merge-conflictsignInFailure コールバックをトリガーします。このエラー オブジェクトには、永続的な認証情報も含まれています。ログインを完了するには、永続的な認証情報によるログインがコールバックでトリガーされる必要があります。auth.signInWithCredential(error.credential) によってログインを完了する前に、匿名ユーザーのデータを保存して匿名ユーザーを削除する必要があります。ログインの完了後、データを匿名以外のユーザーにコピーします。次の例では、このフローがどのように機能するかを示しています。

// Temp variable to hold the anonymous user data if needed.
var data = null;
// Hold a reference to the anonymous current user.
var anonymousUser = firebase.auth().currentUser;
ui.start('#firebaseui-auth-container', {
  // Whether to upgrade anonymous users should be explicitly provided.
  // The user must already be signed in anonymously before FirebaseUI is
  // rendered.
  autoUpgradeAnonymousUsers: true,
  signInSuccessUrl: '<url-to-redirect-to-on-success>',
  signInOptions: [
    firebase.auth.GoogleAuthProvider.PROVIDER_ID,
    firebase.auth.FacebookAuthProvider.PROVIDER_ID,
    firebase.auth.EmailAuthProvider.PROVIDER_ID,
    firebase.auth.PhoneAuthProvider.PROVIDER_ID
  ],
  callbacks: {
    // signInFailure callback must be provided to handle merge conflicts which
    // occur when an existing credential is linked to an anonymous user.
    signInFailure: function(error) {
      // For merge conflicts, the error.code will be
      // 'firebaseui/anonymous-upgrade-merge-conflict'.
      if (error.code != 'firebaseui/anonymous-upgrade-merge-conflict') {
        return Promise.resolve();
      }
      // The credential the user tried to sign in with.
      var cred = error.credential;
      // Copy data from anonymous user to permanent user and delete anonymous
      // user.
      // ...
      // Finish sign-in after data is copied.
      return firebase.auth().signInWithCredential(cred);
    }
  }
});

次のステップ

  • FirebaseUI の使用とカスタマイズについて詳しくは、README をご覧ください。
  • FirebaseUI で見つかった問題を報告するには、GitHub の [Issues] タブを使用してください。