WebOTP API を使用してウェブ上で電話番号を確認する

SMS で受信した OTP についてお客様をサポートする

WebOTP API とは

現在、世界中のほとんどの人がモバイル デバイスを所有しており、デベロッパーはサービスのユーザーの識別子として電話番号を一般的に使用しています。

電話番号の確認方法はさまざまですが、SMS で送信されるランダムに生成されたワンタイム パスワード(OTP)が最も一般的な方法の 1 つです。このコードをデベロッパーのサーバーに送り返すことで、電話番号の所有権を証明します。

このアイデアは、次のような目的を達成するために、すでに多くのシナリオで導入されています。

  • ユーザーの識別子としての電話番号。新しいサービスに登録する際に、一部のウェブサイトではメールアドレスではなく電話番号を求められ、アカウント ID として使用されます。
  • 2 段階認証プロセス。ログイン時に、ウェブサイトでパスワードやその他の知識要素に加えて、SMS で送信されたワンタイム コードが求められます。
  • お支払いの確認。ユーザーが支払いを行う際に、SMS で送信されたワンタイム コードを求めることで、ユーザーの意図を確認できます。

現在のプロセスでは、ユーザーに不便が生じています。SMS メッセージ内の OTP を見つけてフォームにコピー&ペーストするのは面倒で、重要なユーザー ジャーニーでのコンバージョン率が低下します。この緩和は、世界最大規模のデベロッパーの多くからウェブに対する長年のリクエストでした。Android には、まさにこの処理を行う API があります。iOSSafari も同様です。

WebOTP API を使用すると、アプリのドメインにバインドされた特別な形式のメッセージをアプリで受信できます。これにより、SMS メッセージから OTP をプログラムで取得し、ユーザーの電話番号をより簡単に確認できます。

実例を見る

たとえば、ユーザーがウェブサイトで電話番号を確認したいとします。ウェブサイトからユーザーに SMS でテキスト メッセージが送信され、ユーザーがメッセージの OTP を入力して電話番号の所有権を確認します。

WebOTP API を使用すると、動画で示されているように、ユーザーはワンタップでこれらの手順を完了できます。テキスト メッセージが届くと、ボトムシートがポップアップ表示され、電話番号の確認を求めるメッセージが表示されます。ボトムシートの [確認] ボタンをクリックすると、ブラウザが OTP をフォームに貼り付け、ユーザーが [続行] を押すことなくフォームが送信されます。

プロセス全体を次の図に示します。

WebOTP API の図

デモを試してみましょう。電話番号の入力やデバイスへの SMS の送信は求められませんが、デモに表示されたテキストをコピーして別のデバイスから送信することはできます。これは、WebOTP API を使用する場合、送信者が誰であるかは関係ないためです。

  1. Android デバイスの Chrome 84 以降で https://chrome.dev/web-otp-demo にアクセスします。
  2. 別のスマートフォンから、次の SMS テキスト メッセージをスマートフォンに送信します。
Your OTP is: 123456.

@chrome.dev #123456

SMS を受信し、コードを入力するよう求めるプロンプトが入力エリアに表示されましたか? これが、ユーザー向けの WebOTP API の仕組みです。

WebOTP API の使用は、次の 3 つの部分で構成されます。

  • 適切にアノテーションされた <input> タグ
  • ウェブアプリの JavaScript
  • SMS で送信される書式設定されたメッセージ テキスト。

まず <input> タグについて説明します。

<input> タグにアノテーションを付ける

WebOTP 自体は HTML アノテーションなしで動作しますが、クロスブラウザ互換性を確保するため、ユーザーが OTP を入力すると予想される <input> タグに autocomplete="one-time-code" を追加することを強くおすすめします。

これにより、Safari 14 以降では、WebOTP をサポートしていない場合でも、SMS メッセージの形式を設定するで説明されている形式の SMS を受信したときに、<input> フィールドに OTP を自動入力するようユーザーに提案できます。

HTML

<form>
  <input autocomplete="one-time-code" required/>
  <input type="submit">
</form>

WebOTP API を使用する

WebOTP はシンプルなので、次のコードをコピーして貼り付けるだけで済みます。いずれにしても、何が起こっているのかを説明します。

JavaScript

if ('OTPCredential' in window) {
  window.addEventListener('DOMContentLoaded', e => {
    const input = document.querySelector('input[autocomplete="one-time-code"]');
    if (!input) return;
    const ac = new AbortController();
    const form = input.closest('form');
    if (form) {
      form.addEventListener('submit', e => {
        ac.abort();
      });
    }
    navigator.credentials.get({
      otp: { transport:['sms'] },
      signal: ac.signal
    }).then(otp => {
      input.value = otp.code;
      if (form) form.submit();
    }).catch(err => {
      console.log(err);
    });
  });
}

特徴検出

機能検出は、他の多くの API と同じです。DOMContentLoaded イベントをリッスンすると、DOM ツリーのクエリの準備が整うまで待機します。

JavaScript

if ('OTPCredential' in window) {
  window.addEventListener('DOMContentLoaded', e => {
    const input = document.querySelector('input[autocomplete="one-time-code"]');
    if (!input) return;
    
    const form = input.closest('form');
    
  });
}

OTP を処理する

WebOTP API 自体は非常にシンプルです。navigator.credentials.get() を使用して OTP を取得します。WebOTP は、そのメソッドに新しい otp オプションを追加します。プロパティは 1 つだけです。transport の値は、文字列 'sms' を含む配列である必要があります。

JavaScript

    …
    navigator.credentials.get({
      otp: { transport:['sms'] }
      …
    }).then(otp => {
    …

これにより、SMS メッセージが届いたときにブラウザの権限フローがトリガーされます。権限が付与されると、返された Promise は OTPCredential オブジェクトで解決されます。

取得した OTPCredential オブジェクトの内容

{
  code: "123456" // Obtained OTP
  type: "otp"  // `type` is always "otp"
}

次に、OTP 値を <input> フィールドに渡します。フォームを直接送信することで、ユーザーがボタンをタップする必要がなくなります。

JavaScript

    
    navigator.credentials.get({
      otp: { transport:['sms'] }
      
    }).then(otp => {
      input.value = otp.code;
      if (form) form.submit();
    }).catch(err => {
      console.error(err);
    });
    

メッセージを中止する

ユーザーが OTP を手動で入力してフォームを送信した場合は、options オブジェクトAbortController インスタンスを使用して get() 呼び出しをキャンセルできます。

JavaScript

    
    const ac = new AbortController();
    
    if (form) {
      form.addEventListener('submit', e => {
        ac.abort();
      });
    }
    
    navigator.credentials.get({
      otp: { transport:['sms'] },
      signal: ac.signal
    }).then(otp => {
    

SMS メッセージの形式を設定する

API 自体は十分にシンプルに見えますが、使用する前に知っておくべきことがいくつかあります。メッセージは navigator.credentials.get() の呼び出し後に送信する必要があり、get() が呼び出されたデバイスで受信する必要があります。最後に、メッセージは次の形式に準拠する必要があります。

  • メッセージは、4 ~ 10 文字の英数字文字列(少なくとも 1 つの数字を含む)を含む人間が読めるテキストで始まり、最後の行は URL と OTP 用に残されています。
  • API を呼び出したウェブサイトの URL のドメイン部分の前に @ を付ける必要があります。
  • URL には、ポンド記号(「#」)の後に OTP を含める必要があります。

次に例を示します。

Your OTP is: 123456.

@www.example.com #123456

以下に不適切な例を示します。

不正な形式の SMS テキストの例 この方法が機能しない理由
Here is your code for @example.com #123456 @ は、最後の行の最初の文字になることが想定されます。
Your code for @example.com is #123456 @ は、最後の行の最初の文字になることが想定されます。
Your verification code is 123456

@example.com\t#123456
@host#code の間には半角スペースが 1 つ必要です。
Your verification code is 123456

@example.com  #123456
@host#code の間には半角スペースが 1 つ必要です。
Your verification code is 123456

@ftp://example.com #123456
URL スキームを含めることはできません。
Your verification code is 123456

@https://example.com #123456
URL スキームを含めることはできません。
Your verification code is 123456

@example.com:8080 #123456
ポートを含めることはできません。
Your verification code is 123456

@example.com/foobar #123456
パスを含めることはできません。
Your verification code is 123456

@example .com #123456
ドメインに空白文字は使用できません。
Your verification code is 123456

@domain-forbiden-chars-#%/:<>?@[] #123456
ドメインに禁止文字が含まれています。
@example.com #123456

Mambo Jumbo
@host#code は最後の行になることが想定されます。
@example.com #123456

App hash #oudf08lkjsdf834
@host#code は最後の行になることが想定されます。
Your verification code is 123456

@example.com 123456
# がありません。
Your verification code is 123456

example.com #123456
@ がありません。
Hi mom, did you receive my last text @# がありません。

デモ

デモでさまざまなメッセージを試す: https://chrome.dev/web-otp-demo

ソースコードは https://github.com/GoogleChromeLabs/web-identity-demos/tree/main/web-otp-demo で入手できます。

クロスオリジンの iframe から WebOTP を使用する

クロスオリジン iframe に SMS OTP を入力することは、通常、支払い確認、特に 3D セキュアで使用されます。クロスオリジンの iframe をサポートする共通形式を使用することで、WebOTP API はネストされたオリジンにバインドされた OTP を配信します。次に例を示します。

  • ユーザーが shop.example にアクセスして、クレジット カードで靴を購入します。
  • クレジット カード番号を入力すると、統合された決済プロバイダが bank.example のフォームを iframe 内に表示し、ユーザーに電話番号の確認を求めて迅速な購入手続きを行います。
  • bank.example は、ユーザーが入力して本人確認を行えるように、OTP を含む SMS をユーザーに送信します。

クロスオリジン iframe 内から WebOTP API を使用するには、次の 2 つを行う必要があります。

  • SMS テキスト メッセージで、トップフレームのオリジンと iframe のオリジンの両方をアノテーションします。
  • クロスオリジン iframe がユーザーから OTP を直接受け取れるように、権限ポリシーを構成します。
アクション内の iframe 内の WebOTP API。

デモは https://web-otp-iframe-demo.stackblitz.io でお試しいただけます。

SMS テキスト メッセージにバインドされたオリジンをアノテーションする

iframe 内から WebOTP API が呼び出された場合、SMS テキスト メッセージの最終行には、トップフレームのオリジン(@ で始まり)、OTP(# で始まり)、iframe のオリジン(@ で始まる)が含まれている必要があります。

Your verification code is 123456

@shop.example #123456 @bank.exmple

Permissions Policy を構成する

クロスオリジン iframe で WebOTP を使用するには、埋め込み側が otp-credentials 権限ポリシーを介してこの API へのアクセスを許可し、意図しない動作を回避する必要があります。一般に、この目標を達成するには次の 2 つの方法があります。

HTTP ヘッダー経由:

Permissions-Policy: otp-credentials=(self "https://bank.example")

iframe の allow 属性を使用する:

<iframe src="https://bank.example/…" allow="otp-credentials"></iframe>

権限ポリシーを指定する方法のその他の例 をご覧ください。

パソコンで WebOTP を使用する

Chrome では、WebOTP は他のデバイスで受信した SMS をリッスンして、ユーザーがパソコンで電話番号の確認を完了できるようにサポートします。

デスクトップ版の WebOTP API。

この機能を使用するには、パソコン版 Chrome と Android 版 Chrome の両方で同じ Google アカウントにログインする必要があります。

デベロッパーは、モバイル ウェブサイトと同じように、PC 向けウェブサイトに WebOTP API を実装するだけで、特別な方法を使う必要はありません。

詳しくは、WebOTP API を使用してパソコンで電話番号を確認するをご覧ください。

よくある質問

形式が正しいメッセージを送信しているのに、ダイアログが表示されません。何が問題なのでしょうか。

API をテストする際には、次の点に注意してください。

  • 送信者の電話番号が受信者の連絡先リストに含まれている場合、基盤となる SMS User Consent API の設計により、この API はトリガーされません。
  • Android デバイスで仕事用プロファイルを使用しているときに WebOTP が機能しない場合は、個人用プロファイル(SMS メッセージを受信するプロファイルと同じ)に Chrome をインストールして使用してみてください。

形式に戻って、SMS の形式が正しいかどうかを確認します。

この API はブラウザ間で互換性がありますか?

Chromium と WebKit は SMS テキスト メッセージの形式について合意し、Apple は iOS 14 と macOS Big Sur 以降で Safari がこの形式をサポートすることを発表しました。Safari は WebOTP JavaScript API をサポートしていませんが、input 要素に autocomplete=["one-time-code"] を追加すると、SMS メッセージが形式に準拠している場合、デフォルトのキーボードで OTP の入力が自動的に提案されます。

認証方法として SMS を使用しても安全ですか?

SMS OTP は、電話番号が最初に提供されたときに電話番号を確認するのに便利ですが、電話番号はハイジャックされたり、携帯通信会社によって再利用されたりする可能性があるため、再認証に SMS による電話番号の確認を使用する場合は注意が必要です。WebOTP は再認証と復元の便利なメカニズムですが、サービスでは、知識チャレンジなどの追加の要素と組み合わせるか、Web Authentication API を使用して強力な認証を行う必要があります。

Chrome の実装に関するバグはどこに報告すればよいですか?

Chrome の実装にバグが見つかりましたか?

  • crbug.com でバグを報告します。できる限り詳しい情報と、再現するための簡単な手順を記載し、[コンポーネント] を Blink>WebOTP に設定します。

この機能に協力するにはどうすればよいですか?

WebOTP API を使用する予定はありますか?皆様からの公開サポートは、機能の優先順位付けに役立ち、他のブラウザ ベンダーにサポートの重要性を示すことにもつながります。ハッシュタグ #WebOTP を使用して @ChromiumDev にツイートし、どこでどのように使用しているかをお知らせください。

リソース