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().signInAndRetrieveDataWithCredential(credential);

ホワイトリストに登録された電話番号でテストする

Firebase コンソールを使用して、開発用の電話番号をホワイトリストに登録できます。電話番号をホワイトリストに登録すると、次のメリットがあります。

  • 使用量の割り当てを消費することなく電話番号認証をテストできます。
  • 実際の SMS メッセージを送信することなく電話番号認証をテストできます。
  • 同じ電話番号で連続してテストを実施してもスロットルが発生しません。このため、レビュー担当者が偶発的にテストに同じ電話番号を使用しても、アプリストアのレビュー プロセス中に拒否されるリスクが最小限に抑えられます。
  • 追加の作業を必要とせずに開発環境で簡単にテストできます。たとえば、Google Play 開発者サービスを使用せずに iOS シミュレータや Android エミュレータで開発できます。
  • セキュリティ チェックによるブロックが生じない統合テストを作成できます。通常、本番環境の実際の電話番号にはセキュリティ チェックが適用されます。

ホワイトリストに登録する電話番号は、次の要件を満たしている必要があります。

  1. 存在していない架空の番号を使用します。Firebase Authentication では、実際のユーザーが使用している既存の電話番号をホワイトリストに登録することはできません。1 つの選択肢としては、+1 650-555-3434 のように、555 プレフィックス付きの番号を米国のテスト電話番号として使用します。
  2. 長さなどの制約に関して、正しい形式の電話番号を使用する必要があります。番号には、実際のユーザーの電話番号と同じ検証が行われます。
  3. 開発用に最大 10 個の電話番号を追加できます。
  4. 推測が困難なテスト用の電話番号 / コードを使用し、頻繁に変更してください。

電話番号と確認コードをホワイトリストに登録する

  1. Firebase コンソールで [Authentication] セクションを開きます。
  2. [ログイン方法] タブで、[電話番号] をまだ有効にしていない場合は有効にします。
  3. [テスト用の電話番号] アコーディオン メニューを開きます。
  4. テストする電話番号を入力します(例: +1 650-555-3434)。
  5. 特定の番号用の 6 桁の確認コードを入力します(例: 654321)。
  6. 番号を追加します。必要に応じて、電話番号の対応する行にカーソルを合わせてゴミ箱アイコンをクリックすると、電話番号とそのコードを削除できます。

手動テスト

ホワイトリストに登録した電話番号をアプリケーションで直接使用を開始できます。これにより、割り当ての問題やスロットルを発生させることなく、開発段階で手動テストを実施できます。また、Google Play 開発者サービスをインストールすることなく、iOS シミュレータや Android エミュレータから直接テストすることもできます。

ホワイトリストに登録された電話番号を指定して確認コードを送信しても、実際の SMS は送信されません。代わりに、以前に構成した確認コードを入力してログインを完了する必要があります。

ログインが完了すると、その電話番号を使用して Firebase ユーザーが作成されます。そのユーザーの動作やプロパティは実際の電話番号のユーザーと同じであり、また同じ方法で Realtime Database や Cloud Firestore などのサービスにアクセスできます。このプロセス中に作成された ID トークンには、実際の電話番号のユーザーと同じ署名が含まれます。

別の選択肢としては、アクセス制限をさらに厳格にする場合、これらのユーザーにカスタム クレームを介してテスト役割を設定して、架空のユーザーとして区別します。

統合テスト

Firebase Authentication には、手動テスト以外にも、スマートフォン認証テスト用の統合テストの作成に役立つ API が用意されています。これらの API は、ウェブの reCAPTCHA の要件や iOS のサイレント プッシュ通知を無効にすることで、アプリの確認を無効にします。これにより、これらのフローで自動テストを実施でき、実装が容易になります。また、Android で即時確認のフローをテストするための機能も備わっています。

ウェブ上では、appVerificationDisabledForTestingtrue に設定してから firebase.auth.RecaptchaVerifier をレンダリングします。これにより reCAPTCHA が自動的に解決されるため、手動で解決せずに電話番号を渡すことができます。reCAPTCHA が無効になっていても、ホワイトリストに登録されていない電話番号を使用するとログインが完了しません。この API では、ホワイトリストに登録された電話番号のみ使用できます。

// Turn off phone auth app verification.
firebase.auth().settings.appVerificationDisabledForTesting = true;

var phoneNumber = "+16505554567";
var testVerificationCode = "123456";

// This will render a fake reCAPTCHA as appVerificationDisabledForTesting is true.
// This will resolve after rendering without app verification.
var appVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container');
// signInWithPhoneNumber will call appVerifier.verify() which will resolve with a fake
// reCAPTCHA response.
firebase.auth().signInWithPhoneNumber(phoneNumber, appVerifier)
    .then(function (confirmationResult) {
      // confirmationResult can resolve with the whitelisted testVerificationCode above.
      return confirmationResult.confirm(testVerificationCode).
    }).catch(function (error) {
      // Error; SMS not sent
      // ...
    });

アプリの確認が無効になっている場合、可視および不可視の mock reCAPTCHA アプリ ベリファイアの動作は異なります。

  • 可視の reCAPTCHA: 可視の reCAPTCHA が appVerifier.render() を介してレンダリングされると、一瞬遅れて自動的に解決されます。これは、ユーザーがレンダリング時にすぐに reCAPTCHA をクリックするのと同じです。reCAPTCHA 応答はしばらくしてから有効期限が切れ、再度自動解決されます。
  • 不可視の reCAPTCHA: 不可視の reCAPTCHA は、レンダリング時に自動解決されず、appVerifier.verify() 呼び出しで、または reCAPTCHA のボタンアンカーが一瞬遅れてクリックされたときに自動解決されます。同様に、応答はしばらくしてから有効期限が切れ、appVerifier.verify() 呼び出しの後、または reCAPTCHA のボタンアンカーを再度クリックしたときにのみ自動解決されます。

mock reCAPTCHA が解決されると、偽の応答で、対応するコールバック関数が期待通りに起動されます。有効期限のコールバックも指定されている場合は、有効期限が切れるとトリガーされます。

次のステップ

ユーザーが初めてログインすると、新しいユーザー アカウントが作成され、ユーザーがログインに使用した認証情報(ユーザー名とパスワード、電話番号、または認証プロバイダ情報)にアカウントがリンクされます。この新しいアカウントは 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 のサポートページをご覧ください。