JavaScript を使用して電話番号で Firebase 認証を行う

Firebase Authentication を使用すれば、ユーザーのスマートフォンに SMS メッセージを送信することによってユーザーをログインさせることができます。ユーザーは SMS メッセージに記載されたワンタイム コードを使用してログインします。

電話番号ログインをアプリに追加する最も簡単な方法は、FirebaseUI を使用することです。このライブラリには、電話番号ログインのほか、パスワードに基づくログインやフェデレーション ログインのログインフローを実装するドロップイン式のログイン ウィジェットが含まれています。このドキュメントでは、Firebase SDK を使用して電話番号ログインフローを実装する方法について説明します。

始める前に

初期化スニペットを Firebase コンソールからプロジェクトにコピーしていない場合は、Firebase を JavaScript プロジェクトに追加するの説明に沿って初期化スニペットをコピーします。

セキュリティに関する懸念

電話番号の所有権はユーザー間で簡単に移転できるため、電話番号のみを使用する認証は、便利である反面、セキュリティ面では他の認証方法より劣ります。また、複数のユーザー プロフィールを持つ端末では、SMS メッセージを受信できるすべてのユーザーが、端末の電話番号を使用してアカウントにログインできます。

アプリで電話番号ベースのログインを使用する場合は、よりセキュリティの高いログイン方法も同時に提供し、電話番号ログインを使用した場合のセキュリティ面での懸念をユーザーに通知する必要があります。

Firebase プロジェクトで電話番号ログインを有効にする

SMS を介してユーザーをログインさせるには、まず Firebase プロジェクトで電話番号ログイン方法を有効にする必要があります。

  1. Firebase コンソールで [Authentication] セクションを開きます。
  2. [ログイン方法] ページで、[電話番号] のログイン方法を有効にします。
  3. 同じページで、アプリをホストするドメインが [OAuth リダイレクト ドメイン] セクションのリストにない場合は、ドメインを追加します。

Firebase の電話番号ログイン リクエストの割り当ては多めになっており、ほとんどのアプリはこれで十分です。ただし、大量のユーザーを電話認証でログインさせる場合は、料金プランをアップグレードしなければならないことがあります。料金ページをご覧ください。

reCAPTCHA ベリファイアを設定する

電話番号を使ってユーザーをログインさせる前に、Firebase の reCAPTCHA ベリファイアを設定する必要があります。Firebase は不正行為を防ぐ手段として reCAPTCHA を使用します。これにより、たとえば電話番号の確認リクエストがアプリで許可されたドメインから発信されたものかどうかを確認できます。

reCAPTCHA クライアントを手動で設定する必要はありません。Firebase SDK の RecaptchaVerifier オブジェクトを使用すると、必要なクライアント鍵とシークレットが自動的に作成され、処理されます。

RecaptchaVerifier オブジェクトは不可視の reCAPTCHA と reCAPTCHA ウィジェットをどちらもサポートしています。前者を使用すると、通常はユーザーに操作を要求せずにユーザーを確認でき、後者はログインを完了するために常にユーザーの操作を必要とします。

reCAPTCHA をレンダリングする前に Auth インスタンスの言語コードを更新することによって、元のテキスト画像の reCAPTCHA をユーザーの設定に合わせてローカライズすることができます。前述のローカリゼーションは、ユーザーに送信される SMS メッセージ(確認コードを含む)にも適用されます。

firebase.auth().languageCode = 'it';
// To apply the default browser preference instead of explicitly setting it.
// firebase.auth().useDeviceLanguage();

不可視の reCAPTCHA を使用する

不可視の reCAPTCHA を使用するには、size パラメータを invisible に設定して RecaptchaVerifier オブジェクトを作成し、ログイン フォームを送信するボタンの ID を指定します。次に例を示します。

window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('sign-in-button', {
  'size': 'invisible',
  'callback': function(response) {
    // reCAPTCHA solved, allow signInWithPhoneNumber.
    onSignInSubmit();
  }
});

reCAPTCHA ウィジェットを使用する

可視の reCAPTCHA ウィジェットを使用するには、ウィジェットを含む要素をページに作成してから、そのコンテナの ID を指定して RecaptchaVerifier オブジェクトを作成します。次に例を示します。

window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container');

オプション: reCAPTCHA パラメータを指定する

必要に応じて、ユーザーが reCAPTCHA を解決したとき、またはユーザーがフォームを送信する前に reCAPTCHA が期限切れになったときに呼び出されるコールバック関数を RecaptchaVerifier オブジェクトに設定できます。

window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container', {
  'size': 'normal',
  'callback': function(response) {
    // reCAPTCHA solved, allow signInWithPhoneNumber.
    // ...
  },
  'expired-callback': function() {
    // Response expired. Ask user to solve reCAPTCHA again.
    // ...
  }
});

オプション: reCAPTCHA を事前レンダリングする

ログイン リクエストを送信する前に reCAPTCHA を事前レンダリングする場合は、render を呼び出します。

recaptchaVerifier.render().then(function(widgetId) {
  window.recaptchaWidgetId = widgetId;
});

render が解決された後、reCAPTCHA のウィジェット ID を取得します。これを使用して reCAPTCHA API を呼び出すことができます。

var recaptchaResponse = grecaptcha.getResponse(window.recaptchaWidgetId);

ユーザーのスマートフォンに確認コードを送信する

電話番号ログインを開始するには、ユーザーに電話番号の入力を求めるインターフェースを表示した後、signInWithPhoneNumber を呼び出して、ユーザーのスマートフォンに認証コードを SMS で送信するよう Firebase にリクエストします。

  1. ユーザーの電話番号を取得します。

    法的要件はさまざまに異なりますが、電話番号ログインを使用する場合は確認用の SMS メッセージが送られること、それには標準料金がかかることをユーザーに知らせることをおすすめします。そうすることで、ユーザーもそのように心構えできます。

  2. signInWithPhoneNumber を呼び出し、ユーザーの電話番号と前の手順で作成した RecaptchaVerifier を渡します。
    var phoneNumber = getPhoneNumberFromUserInput();
    var appVerifier = window.recaptchaVerifier;
    firebase.auth().signInWithPhoneNumber(phoneNumber, appVerifier)
        .then(function (confirmationResult) {
          // SMS sent. Prompt user to type the code from the message, then sign the
          // user in with confirmationResult.confirm(code).
          window.confirmationResult = confirmationResult;
        }).catch(function (error) {
          // Error; SMS not sent
          // ...
        });
    
    signInWithPhoneNumber の結果がエラーであった場合は、ユーザーが再試行できるように reCAPTCHA をリセットします。
    grecaptcha.reset(window.recaptchaWidgetId);
    
    // Or, if you haven't stored the widget ID:
    window.recaptchaVerifier.render().then(function(widgetId) {
      grecaptcha.reset(widgetId);
    }
    

signInWithPhoneNumber メソッドは reCAPTCHA 画像をユーザーに発行し、ユーザーが画像認証に正しく回答すると、確認コードを含む SMS メッセージをユーザーのスマートフォンに送信します。

確認コードを使ってユーザーをログインさせる

signInWithPhoneNumber の呼び出しが成功したら、SMS で届いた確認コードを入力するようユーザーに求めます。次に、signInWithPhoneNumber のフルフィルメント ハンドラ(すなわち、その then ブロック)に渡された ConfirmationResult オブジェクトの confirm メソッドに確認コードを渡してユーザーをログインさせます。次に例を示します。

var code = getCodeFromUserInput();
confirmationResult.confirm(code).then(function (result) {
  // User signed in successfully.
  var user = result.user;
  // ...
}).catch(function (error) {
  // User couldn't sign in (bad verification code?)
  // ...
});

confirm の呼び出しが成功すると、ユーザーは正常にログインされます。

中間の AuthCredential オブジェクトを取得する

ユーザーのアカウントの AuthCredential オブジェクトを取得する場合は、confirm を呼び出す代わりに、confirmationResult からの確認 ID と確認コードを PhoneAuthProvider.credential に渡します。

var credential = firebase.auth.PhoneAuthProvider.credential(confirmationResult.verificationId, code);

この認証情報を使ってユーザーをログインさせることができます。

firebase.auth().signInWithCredential(credential);

次のステップ

ユーザーが初めてログインすると、新しいユーザー アカウントが作成され、ユーザーがログインに使用した認証情報(ユーザー名とパスワード、電話番号、または認証プロバイダ情報)にアカウントがリンクされます。この新しいアカウントは Firebase プロジェクトの一部として保存され、ユーザーのログイン方法にかかわらず、プロジェクトのすべてのアプリでユーザーを識別するために使用できます。

  • アプリでユーザーの認証ステータスを把握するには、Auth オブジェクトにオブザーバーを設定することをおすすめします。これによって、ユーザーの基本的なプロフィール情報を User オブジェクトから取得できます。ユーザーの管理についての記事をご覧ください。

  • Firebase Realtime Database と Cloud Storage のセキュリティ ルールでは、ログイン済みユーザーの一意のユーザー ID を auth 変数から取得し、それを使用してどのデータをユーザーからアクセス可能にするかを制御できます。

既存のユーザー アカウントに認証プロバイダの認証情報をリンクすることで、ユーザーが複数の認証プロバイダを使用してアプリにログインできるようになります。

ユーザーのログアウトを行うには signOut を呼び出します。

firebase.auth().signOut().then(function() {
  // Sign-out successful.
}).catch(function(error) {
  // An error happened.
});

フィードバックを送信...

ご不明な点がありましたら、Google のサポートページをご覧ください。