SMS で受信した OTP についてユーザーをサポートする
WebOTP API とは何ですか?
現在、世界中のほとんどの人がモバイル デバイスを所有しており、デベロッパーはサービス ユーザーの識別子として電話番号を使用することが一般的です。
電話番号を確認する方法はいくつかありますが、SMS で送信されるランダムに生成されたワンタイム パスワード(OTP)が最も一般的です。このコードをデベロッパーのサーバーに送り返すことで、電話番号を制御していることを証明します。
この考え方は、次のような多くのシナリオですでに実装されています。
- ユーザーの識別子としての電話番号。新しいサービスに登録する際に、メールアドレスではなく電話番号を入力するよう求められ、その電話番号がアカウント識別子として使用されるウェブサイトもあります。
- 2 段階認証プロセス:ログイン時に、ウェブサイトから、セキュリティ強化のため、パスワードなどの知識認証情報に加えて SMS で送信されるワンタイム コードの入力を求められます。
- お支払いの確認。ユーザーが支払いを行う際に、SMS で送信されるワンタイム コードを要求すると、ユーザーの意図を確認できます。
現在のプロセスはユーザーにとって煩わしいものです。SMS メッセージ内の OTP を見つけて、フォームにコピーして貼り付けるのは手間がかかり、重要なユーザー ジャーニーでコンバージョン率が低下します。これを緩和することは、世界最大のデベロッパーの多くから長い間リクエストされていたウェブに関する要望でした。Android には、まさにこのことを実行する API があります。iOS と Safari も同様です。
WebOTP API を使用すると、アプリはアプリのドメインにバインドされた特別な形式のメッセージを受信できます。これにより、SMS メッセージから OTP をプログラムで取得し、ユーザーの電話番号をより簡単に確認できます。
実例を見る
ユーザーがウェブサイトで電話番号を確認したいとします。ウェブサイトから SMS でテキスト メッセージがユーザーに送信され、ユーザーはメッセージに記載された OTP を入力して電話番号の所有権を確認します。
WebOTP API を使用すると、これらの手順は動画で示されているように、ユーザーが 1 回タップするだけで完了します。テキスト メッセージが届くと、ボトムシートがポップアップ表示され、電話番号の確認を求めるメッセージが表示されます。下部シートの [確認] ボタンをクリックすると、ブラウザが OTP をフォームに貼り付け、ユーザーが [続行] を押さなくてもフォームが送信されます。
プロセス全体を図にすると、次のようになります。
デモを試す。電話番号の入力やデバイスへの SMS の送信は行われませんが、デモに表示されたテキストをコピーして別のデバイスから送信することはできます。これは、WebOTP API を使用する場合、送信者が誰であるかは関係ないためです。
- Android デバイスで Chrome 84 以降を使用して https://web-otp.glitch.me にアクセスします。
- 別のスマートフォンから、スマートフォンに次の SMS テキスト メッセージを送信します。
Your OTP is: 123456.
@web-otp.glitch.me #12345
SMS を受信し、入力エリアにコードを入力するよう求めるメッセージが表示されましたか?これが、ユーザーにとっての WebOTP API の仕組みです。
WebOTP API の使用は、次の 3 つの部分で構成されています。
- 適切にアノテーションが付けられた
<input>
タグ - ウェブアプリの JavaScript
- SMS で送信されるフォーマットされたメッセージ テキスト。
まず <input>
タグについて説明します。
<input>
タグにアノテーションを付ける
WebOTP 自体は HTML アノテーションなしで動作しますが、クロスブラウザの互換性を確保するため、ユーザーが OTP を入力すると想定される <input>
タグに autocomplete="one-time-code"
を追加することを強くおすすめします。
これにより、Safari 14 以降では、SMS メッセージをフォーマットするで説明されている形式の SMS を受信したときに、WebOTP をサポートしていない場合でも、ユーザーに <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
オプションが追加されます。プロパティは 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://web-otp.glitch.me)でさまざまなメッセージを試す。
フォークして独自のバージョンを作成することもできます(https://glitch.com/edit/#!/web-otp)。
クロスオリジンの iframe から WebOTP を使用する
クロスオリジン iframe への SMS OTP の入力は、通常、お支払いの確認(特に 3D Secure の場合)に使用されます。クロスオリジン iframe をサポートする共通形式を持つ WebOTP API は、ネストされたオリジンにバインドされた OTP を提供します。次に例を示します。
- ユーザーが
shop.example
にアクセスして、クレジット カードで靴を購入します。 - クレジット カード番号を入力すると、統合された支払いプロバイダが iframe 内に
bank.example
のフォームを表示し、ユーザーに電話番号の確認を求めて、迅速な購入手続きを促します。 bank.example
は、OTP を含む SMS をユーザーに送信します。ユーザーは、OTP を入力して本人確認を行うことができます。
クロスオリジン iframe 内から WebOTP API を使用するには、次の 2 つのことを行います。
- SMS テキスト メッセージで、トップフレームのオリジンと iframe オリジンの両方にアノテーションを付けます。
- クロスオリジン iframe がユーザーから OTP を直接受け取れるように、権限ポリシーを構成します。
デモは https://web-otp-iframe-demo.stackblitz.io で試すことができます。
SMS テキスト メッセージにバウンド送信元のアノテーションを付ける
WebOTP API が iframe 内から呼び出される場合は、SMS テキスト メッセージに、@
の後にトップフレームのオリジン、#
の後に OTP、最後の行に @
の後に iframe オリジンを含める必要があります。
Your verification code is 123456
@shop.example #123456 @bank.exmple
権限ポリシーを構成する
クロスオリジン 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 のリッスニングをサポートし、ユーザーがパソコンで電話番号の確認を完了できるようにしています。
この機能を使用するには、パソコン版 Chrome と Android 版 Chrome の両方で同じ Google アカウントにログインする必要があります。
デベロッパーは、モバイル ウェブサイトと同じように、デスクトップ ウェブサイトに 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 を使用する予定はありますか?一般公開されたサポートは、Google が機能の優先順位を決める際に役立ち、他のブラウザ ベンダーにその機能のサポートがどれほど重要であるかを示します。ハッシュタグ #WebOTP
を使用して @ChromiumDev にツイートを送信し、どこでどのように使用しているかをお知らせください。