SMS で受信した OTP についてお客様をサポートする
WebOTP API とは
昨今では、世界中のほとんどの人がモバイル デバイスを所有しており、サービスのユーザーの識別子として電話番号を使用するのが一般的です。
電話番号の確認にはさまざまな方法がありますが、SMS によってランダムに生成されるワンタイム パスワード(OTP)が最も一般的な方法の一つです。このコードをデベロッパーのサーバーに送信すると、電話番号が制御されていることがわかります。
このアイデアは、以下を実現するための多くのシナリオですでにデプロイされています。
- ユーザーの ID としての電話番号。一部のウェブサイトでは、新しいサービスに登録する際に、メールアドレスではなく電話番号を要求し、それをアカウント ID として使用します。
- 2 段階認証プロセス。ウェブサイトがログインする際、セキュリティ強化のためにパスワードなどの知識要素に加えて、SMS でワンタイム コードを送信するよう求めます。
- お支払いの確認。ユーザーが支払いを行う際に、SMS でワンタイム コードを尋ねることで、ユーザーの意図を確認できます。
現在のプロセスではユーザーに負担がかかります。SMS メッセージ内で OTP を見つけ、それをコピーしてフォームに貼り付けるのは面倒な作業であり、クリティカル ユーザー ジャーニーでのコンバージョン率が低下します。世界最大手のデベロッパーの多くは、これを容易に実現できるようにウェブを求めてきました。Android には、これを行う API があります。iOS や Safari も同様です。
WebOTP API を使用すると、アプリのドメインにバインドされた専用形式のメッセージをアプリで受信できます。これにより、SMS メッセージから OTP をプログラムで取得し、ユーザーの電話番号をより簡単に確認できます。
実例を見る
たとえば、ユーザーがウェブサイトで電話番号を確認したいとします。ウェブサイトが SMS でユーザーにテキスト メッセージを送信します。ユーザーはメッセージの OTP を入力して、電話番号の所有権を確認します。
動画で示されているように、WebOTP API を使用すると、ユーザーはワンタップでこれらの手順を簡単に実行できます。テキスト メッセージを受信すると、ボトムシートがポップアップし、電話番号の確認を求めるプロンプトをユーザーに表示します。ボトムシートの [Verify] ボタンをクリックすると、ブラウザによって OTP がフォームに貼り付けられます。フォームはユーザーが [Continue] を押さなくても送信されます。
このプロセスの全体は、次の図のようになります。

ご自身でデモをお試しください。電話番号の入力を求められたり、デバイスに 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 文字の英数字の文字列と、URL と OTP の最後の行から少なくとも 1 つの数字が残っています。
- 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 セキュアで支払いの確認に使用されます。クロスオリジンの iframe をサポートする共通の形式を使用する WebOTP API は、ネストされたオリジンにバインドされた OTP を配信します。次に例を示します。
- あるユーザーが
shop.example
にアクセスし、クレジット カードで靴を購入しました。 - クレジット カード番号を入力すると、統合された決済機関が iframe 内に
bank.example
のフォームを表示し、購入手続きを迅速に行うために電話番号を確認するようユーザーに求めます。 bank.example
は、OTP を含む SMS をユーザーに送信し、ユーザーがそれを入力して本人確認を行えるようにします。
クロスオリジンの iframe 内から WebOTP API を使用するには、次の 2 つのことを行う必要があります。
- SMS テキスト メッセージで、トップフレームのオリジンと iframe のオリジンの両方にアノテーションを付けます。
- クロスオリジンの iframe がユーザーから直接 OTP を受信できるように、権限ポリシーを構成します。
デモは https://web-otp-iframe-demo.stackblitz.io でお試しいただけます。
バインドされた送信元に SMS テキスト メッセージにアノテーションを付ける
WebOTP API を iframe 内から呼び出す場合、SMS テキスト メッセージでは、先頭の @
と OTP の順の最上フレームオリジンと、#
で始まる 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 テキスト メッセージの形式について合意しており、iOS 14 と macOS Big Sur から Apple は Safari のサポートを発表しました。Safari は WebOTP JavaScript API をサポートしていませんが、input
要素に autocomplete=["one-time-code"]
アノテーションを付けることで、SMS メッセージがこの形式に準拠している場合、デフォルトのキーボードにより OTP を入力するよう自動的に提案されます。
認証方法として SMS を使用しても安全ですか?
SMS OTP は、電話番号を最初に提供されたときに電話番号を確認するのに便利ですが、電話番号が携帯通信会社によって乗っ取られたり、再利用されたりする可能性があるため、SMS による電話番号確認は再認証時に慎重に使用する必要があります。WebOTP は便利な再認証と復元のメカニズムですが、サービスはそれをナレッジ チャレンジなどのその他の要素と組み合わせるか、強力な認証のために Web Authentication API を使用する必要があります。
Chrome の実装に関するバグを報告するにはどうすればよいですか?
Chrome の実装にバグが見つかりましたか?
- https://new.crbug.com でバグを報告します。できるだけ詳しい情報と簡単な再現手順を記載して、[Components] を
Blink>WebOTP
に設定します。
この機能についてどのようにサポートすればよいですか?
WebOTP API を使用する予定はありますか?公開サポートによって、Google は各機能に優先順位を付けることができます。また、それらの機能をサポートすることがいかに重要であるかを他のブラウザ ベンダーに示すことができます。ハッシュタグ #WebOTP
を使って @ChromiumDev にツイートを送信し、どこでどのように使用されているかを教えてください。