SMS で受信した OTP についてお客様をサポートする
WebOTP API とは
最近では、世界中のほとんどの人がモバイル デバイスを所有しており、デベロッパーはサービス ユーザーの識別子として電話番号を使用するのが一般的です。
電話番号の確認にはさまざまな方法がありますが、SMS によってランダムに生成されるワンタイム パスワード(OTP)が最も一般的な方法の 1 つです。このコードをデベロッパーのサーバーに送信すると、電話番号を制御することができます。
この考え方はすでに多くのシナリオで採用されており、
- ユーザーの ID としての電話番号。ウェブサイトによっては、新しいサービスに登録する際に、メールアドレスではなく電話番号を尋ねて、アカウント ID として使用することがあります。
- 2 段階認証プロセス。ウェブサイトはログイン時に、セキュリティを強化するため、パスワードなどの知識要素に加えて、SMS でワンタイム コードを SMS で送信するように要求します。
- お支払いの確認。ユーザーが支払いを行う際に、SMS でワンタイム コードをリクエストすることで、ユーザーの意図を確認できます。
現在のプロセスではユーザーに負担がかかります。SMS メッセージ内の OTP を見つけてコピーし、フォームに貼り付けるという作業は煩雑で、クリティカル ユーザー ジャーニーにおけるコンバージョン率が低下します。これを緩和したいという要望は、世界中の多くの大手デベロッパーからウェブに対する要望を受けていました。Android には、この処理を行う API があります。iOS と Safari についても同様です。
WebOTP API を使用すると、アプリは、アプリのドメインにバインドされた特殊な形式のメッセージを受信できます。これにより、SMS メッセージからプログラムで OTP を取得し、ユーザーの電話番号を簡単に確認できます。
実例を見る
ユーザーがウェブサイトで電話番号の確認を希望しているとします。ウェブサイトは SMS でユーザーにテキスト メッセージを送信し、ユーザーはメッセージから OTP を入力して電話番号の所有権を確認します。
動画に示されているように、WebOTP API を使用すると、ユーザーはワンタップでこれらの手順を簡単に実行できます。テキスト メッセージが届くと、ボトムシートがポップアップされ、電話番号の確認を求めるメッセージが表示されます。ボトムシートの [確認] ボタンをクリックすると、ブラウザによって 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 を取得します。このメソッドに新しい otp
オプションが追加されました。プロパティ transport
は 1 つだけです。このプロパティの値は、文字列 '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 を使用する
特に 3D セキュアでは、通常、クロスオリジンの iframe に SMS OTP を入力することで、支払いの確認が行われます。クロスオリジンの 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 はモバイルサイトと同様に PC サイトにも実装する必要がありますが、特別な操作は必要ありません。
詳しくは、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 の実装にバグが見つかりましたか?
- https://new.crbug.com でバグを報告します。できる限り詳細かつ簡単な再現手順を記載し、[Components] を
Blink>WebOTP
に設定します。
この機能を使うにはどうすればよいですか?
WebOTP API を使用する予定はありますか?皆様のご協力のおかげで、Google では機能に優先順位を付け、そのサポートがいかに重要であるかを他のブラウザ ベンダーに示すことができます。ハッシュタグ #WebOTP
を使用して @ChromiumDev 宛てにツイートを送信し、使用場所と使用方法をお知らせください。