Xác minh số điện thoại trên web bằng API WebOTP

Hỗ trợ người dùng về mã OTP nhận được qua SMS

WebOTP API là gì?

Ngày nay, hầu hết mọi người trên thế giới đều sở hữu một thiết bị di động và các nhà phát triển thường sử dụng số điện thoại làm giá trị nhận dạng cho người dùng dịch vụ của họ.

Có nhiều cách để xác minh số điện thoại, nhưng mật khẩu một lần (OTP) được tạo ngẫu nhiên và gửi qua SMS là một trong những cách phổ biến nhất. Việc gửi mã này trở lại máy chủ của nhà phát triển cho thấy quyền kiểm soát số điện thoại.

Ý tưởng này đã được triển khai trong nhiều trường hợp để đạt được:

  • Số điện thoại làm giá trị nhận dạng cho người dùng. Khi đăng ký một dịch vụ mới, một số trang web yêu cầu số điện thoại thay vì địa chỉ email và sử dụng số điện thoại đó làm giá trị nhận dạng tài khoản.
  • Xác minh 2 bước. Khi đăng nhập, trang web sẽ yêu cầu mã một lần được gửi qua SMS cùng với mật khẩu hoặc yếu tố nhận dạng khác để tăng cường bảo mật.
  • Xác nhận thanh toán. Khi người dùng thanh toán, việc yêu cầu mã một lần được gửi qua SMS có thể giúp xác minh ý định của người đó.

Quy trình hiện tại gây khó khăn cho người dùng. Việc tìm mã OTP trong tin nhắn SMS, sau đó sao chép và dán mã đó vào biểu mẫu sẽ rất cồng kềnh, làm giảm tỷ lệ chuyển đổi trong các hành trình quan trọng của người dùng. Việc giảm thiểu vấn đề này đã là yêu cầu lâu nay của nhiều nhà phát triển lớn nhất trên thế giới đối với web. Android có một API thực hiện chính xác việc này. iOSSafari cũng vậy.

API WebOTP cho phép ứng dụng của bạn nhận được các thông báo được định dạng đặc biệt liên kết với miền của ứng dụng. Từ đó, bạn có thể lấy OTP từ tin nhắn SMS theo phương thức lập trình và xác minh số điện thoại cho người dùng dễ dàng hơn.

Xem ví dụ thực tiễn

Giả sử một người dùng muốn xác minh số điện thoại của họ với một trang web. Trang web gửi tin nhắn văn bản đến người dùng qua SMS và người dùng nhập mã OTP trong tin nhắn để xác minh quyền sở hữu số điện thoại.

Với API WebOTP, người dùng chỉ cần nhấn một lần là có thể thực hiện các bước này, như minh hoạ trong video. Khi tin nhắn văn bản đến, một bảng dưới cùng sẽ bật lên và nhắc người dùng xác minh số điện thoại của họ. Sau khi nhấp vào nút Xác minh trên trang dưới cùng, trình duyệt sẽ dán mã OTP vào biểu mẫu và gửi biểu mẫu mà người dùng không cần nhấn vào Tiếp tục.

Toàn bộ quy trình được trình bày trong sơ đồ dưới đây.

Sơ đồ API WebOTP

Hãy tự thử bản minh hoạ. Ứng dụng này không yêu cầu số điện thoại của bạn hoặc gửi tin nhắn SMS đến thiết bị của bạn, nhưng bạn có thể gửi tin nhắn từ một thiết bị khác bằng cách sao chép văn bản hiển thị trong bản minh hoạ. Điều này hoạt động vì không quan trọng người gửi là ai khi sử dụng API WebOTP.

  1. Truy cập vào https://web-otp.glitch.me trong Chrome 84 trở lên trên thiết bị Android.
  2. Gửi tin nhắn SMS sau đây từ một điện thoại khác đến điện thoại của bạn.
Your OTP is: 123456.

@web-otp.glitch.me #12345

Bạn có nhận được tin nhắn SMS và thấy lời nhắc nhập mã vào khu vực nhập không? Đó là cách API WebOTP hoạt động cho người dùng.

Việc sử dụng API WebOTP bao gồm ba phần:

  • Thẻ <input> được chú thích đúng cách
  • JavaScript trong ứng dụng web
  • Văn bản tin nhắn được định dạng được gửi qua SMS.

Trước tiên, tôi sẽ trình bày về thẻ <input>.

Chú thích thẻ <input>

Bản thân WebOTP hoạt động mà không cần chú thích HTML nào, nhưng để có khả năng tương thích trên nhiều trình duyệt, bạn nên thêm autocomplete="one-time-code" vào thẻ <input> mà bạn muốn người dùng nhập OTP.

Điều này cho phép Safari 14 trở lên đề xuất người dùng tự động điền trường <input> bằng OTP khi họ nhận được tin nhắn SMS có định dạng được mô tả trong phần Định dạng tin nhắn SMS, mặc dù Safari không hỗ trợ WebOTP.

HTML

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

Sử dụng API WebOTP

Vì WebOTP rất đơn giản, bạn chỉ cần sao chép và dán mã sau đây là xong. Dù sao thì tôi cũng sẽ hướng dẫn bạn về những gì đang diễn ra.

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);
    });
  });
}

Phát hiện tính năng

Việc phát hiện tính năng cũng giống như đối với nhiều API khác. Việc nghe sự kiện DOMContentLoaded sẽ chờ cây DOM sẵn sàng để truy vấn.

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');
    
  });
}

Xử lý OTP

Bản thân API WebOTP khá đơn giản. Sử dụng navigator.credentials.get() để lấy mã OTP. WebOTP thêm một tuỳ chọn otp mới vào phương thức đó. Lớp này chỉ có một thuộc tính: transport, giá trị của thuộc tính này phải là một mảng có chuỗi 'sms'.

JavaScript

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

Thao tác này sẽ kích hoạt quy trình cấp quyền của trình duyệt khi có tin nhắn SMS đến. Nếu quyền được cấp, lời hứa được trả về sẽ phân giải bằng đối tượng OTPCredential.

Nội dung của đối tượng OTPCredential đã lấy được

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

Tiếp theo, hãy truyền giá trị OTP vào trường <input>. Việc gửi trực tiếp biểu mẫu sẽ loại bỏ bước yêu cầu người dùng nhấn vào một nút.

JavaScript

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

Huỷ gửi thư

Trong trường hợp người dùng tự nhập mã OTP và gửi biểu mẫu, bạn có thể huỷ lệnh gọi get() bằng cách sử dụng thực thể AbortController trong đối tượng options.

JavaScript

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

Định dạng tin nhắn SMS

Bản thân API này trông khá đơn giản, nhưng bạn nên biết một số điều trước khi sử dụng. Thông báo phải được gửi sau khi navigator.credentials.get() được gọi và phải được nhận trên thiết bị mà get() được gọi. Cuối cùng, thông báo phải tuân theo định dạng sau:

  • Thông báo bắt đầu bằng văn bản (không bắt buộc) mà con người có thể đọc được, chứa một chuỗi ký tự chữ và số từ 4 đến 10 ký tự, trong đó có ít nhất một số để dành dòng cuối cùng cho URL và OTP.
  • Phần miền của URL của trang web đã gọi API phải đứng trước @.
  • URL phải chứa ký hiệu dấu thăng ("#") theo sau là mã OTP.

Ví dụ:

Your OTP is: 123456.

@www.example.com #123456

Sau đây là một số ví dụ không phù hợp:

Ví dụ về văn bản SMS có định dạng không chính xác Lý do phương thức này không hoạt động
Here is your code for @example.com #123456 @ dự kiến sẽ là ký tự đầu tiên của dòng cuối cùng.
Your code for @example.com is #123456 @ dự kiến sẽ là ký tự đầu tiên của dòng cuối cùng.
Your verification code is 123456

@example.com\t#123456
Dự kiến sẽ có một dấu cách giữa @host#code.
Your verification code is 123456

@example.com  #123456
Dự kiến sẽ có một dấu cách giữa @host#code.
Your verification code is 123456

@ftp://example.com #123456
Không được thêm giao thức URL.
Your verification code is 123456

@https://example.com #123456
Không được thêm giao thức URL.
Your verification code is 123456

@example.com:8080 #123456
Không được bao gồm cổng.
Your verification code is 123456

@example.com/foobar #123456
Không được thêm đường dẫn.
Your verification code is 123456

@example .com #123456
Không có khoảng trắng trong miền.
Your verification code is 123456

@domain-forbiden-chars-#%/:<>?@[] #123456
Không có ký tự bị cấm trong miền.
@example.com #123456

Mambo Jumbo
@host#code dự kiến sẽ là dòng cuối cùng.
@example.com #123456

App hash #oudf08lkjsdf834
@host#code dự kiến sẽ là dòng cuối cùng.
Your verification code is 123456

@example.com 123456
Thiếu #.
Your verification code is 123456

example.com #123456
Thiếu @.
Hi mom, did you receive my last text Thiếu @#.

Bản thu thử

Thử nhiều thông báo bằng bản minh hoạ: https://web-otp.glitch.me

Bạn cũng có thể phân nhánh và tạo phiên bản của riêng mình: https://glitch.com/edit/#!/web-otp.

Sử dụng WebOTP từ một iframe trên nhiều nguồn gốc

Việc nhập mã OTP qua SMS vào iframe trên nhiều nguồn gốc thường được dùng để xác nhận thanh toán, đặc biệt là với 3D Secure. Có định dạng chung để hỗ trợ các iframe trên nhiều nguồn gốc, WebOTP API phân phối OTP liên kết với các nguồn gốc lồng nhau. Ví dụ:

  • Người dùng truy cập vào shop.example để mua một đôi giày bằng thẻ tín dụng.
  • Sau khi nhập số thẻ tín dụng, nhà cung cấp dịch vụ thanh toán tích hợp sẽ hiển thị một biểu mẫu từ bank.example trong một iframe yêu cầu người dùng xác minh số điện thoại để thanh toán nhanh.
  • bank.example gửi tin nhắn SMS chứa mã OTP cho người dùng để họ có thể nhập mã đó nhằm xác minh danh tính của mình.

Để sử dụng API WebOTP từ trong một iframe nhiều nguồn gốc, bạn cần làm hai việc:

  • Chú thích cả nguồn gốc khung trên cùng và nguồn gốc iframe trong thông báo văn bản qua SMS.
  • Định cấu hình chính sách quyền để cho phép iframe trên nhiều nguồn gốc nhận trực tiếp OTP từ người dùng.
WebOTP API trong một iframe đang hoạt động.

Bạn có thể dùng thử bản minh hoạ tại https://web-otp-iframe-demo.stackblitz.io.

Chú thích nguồn gốc liên kết đến tin nhắn văn bản SMS

Khi WebOTP API được gọi từ trong một iframe, tin nhắn văn bản SMS phải bao gồm nguồn gốc khung trên cùng đứng trước @, theo sau là OTP đứng trước # và nguồn gốc iframe đứng trước @ ở dòng cuối cùng.

Your verification code is 123456

@shop.example #123456 @bank.exmple

Định cấu hình Chính sách về quyền

Để sử dụng WebOTP trong một iframe nhiều nguồn gốc, trình nhúng phải cấp quyền truy cập vào API này thông qua chính sách về quyền của thông tin xác thực otp để tránh hành vi ngoài ý muốn. Nói chung, có hai cách để đạt được mục tiêu này:

thông qua Tiêu đề HTTP:

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

thông qua thuộc tính allow của iframe:

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

Xem các ví dụ khác về cách chỉ định chính sách quyền .

Sử dụng WebOTP trên máy tính

Trong Chrome, WebOTP hỗ trợ nghe tin nhắn SMS nhận được trên các thiết bị khác để hỗ trợ người dùng hoàn tất quy trình xác minh số điện thoại trên máy tính.

WebOTP API trên máy tính.

Để sử dụng tính năng này, người dùng phải đăng nhập vào cùng một Tài khoản Google trên cả Chrome dành cho máy tính và Chrome dành cho Android.

Tất cả nhà phát triển chỉ cần triển khai API WebOTP trên trang web dành cho máy tính, giống như cách họ triển khai trên trang web dành cho thiết bị di động, nhưng không cần phải làm gì đặc biệt.

Tìm hiểu thêm thông tin chi tiết tại bài viết Xác minh số điện thoại trên máy tính bằng WebOTP API.

Câu hỏi thường gặp

Hộp thoại không xuất hiện mặc dù tôi đang gửi một thông báo được định dạng đúng cách. Đã xảy ra lỗi gì?

Có một số lưu ý khi kiểm thử API:

  • Nếu số điện thoại của người gửi có trong danh bạ của người nhận, thì API này sẽ không được kích hoạt do thiết kế của API đồng ý của người dùng qua SMS cơ bản.
  • Nếu bạn đang sử dụng hồ sơ công việc trên thiết bị Android và WebOTP không hoạt động, hãy thử cài đặt và sử dụng Chrome trên hồ sơ cá nhân (tức là cùng hồ sơ mà bạn nhận được tin nhắn SMS).

Hãy kiểm tra lại định dạng để xem tin nhắn SMS của bạn có được định dạng chính xác hay không.

API này có tương thích giữa các trình duyệt không?

Chromium và WebKit đã đồng ý về định dạng tin nhắn văn bản SMSApple đã thông báo về việc Safari hỗ trợ định dạng này kể từ iOS 14 và macOS Big Sur. Mặc dù Safari không hỗ trợ API JavaScript WebOTP, nhưng bằng cách chú thích phần tử input bằng autocomplete=["one-time-code"], bàn phím mặc định sẽ tự động đề xuất bạn nhập OTP nếu tin nhắn SMS tuân thủ định dạng.

Có an toàn khi sử dụng SMS làm phương thức xác thực không?

Mặc dù mã OTP qua SMS rất hữu ích để xác minh số điện thoại khi số điện thoại được cung cấp lần đầu, nhưng bạn phải sử dụng tính năng xác minh số điện thoại qua SMS một cách thận trọng để xác thực lại vì các nhà mạng có thể xâm nhập và tái sử dụng số điện thoại. WebOTP là một cơ chế xác thực lại và khôi phục thuận tiện, nhưng các dịch vụ nên kết hợp cơ chế này với các yếu tố bổ sung, chẳng hạn như câu đố kiến thức hoặc sử dụng API xác thực web để xác thực mạnh.

Tôi có thể báo cáo lỗi trong quá trình triển khai Chrome ở đâu?

Bạn có phát hiện lỗi khi triển khai Chrome không?

  • Gửi lỗi tại crbug.com. Cung cấp càng nhiều thông tin chi tiết càng tốt, hướng dẫn đơn giản để tái tạo lỗi và đặt Components (Thành phần) thành Blink>WebOTP.

Tôi có thể giúp gì cho tính năng này?

Bạn có định sử dụng API WebOTP không? Sự ủng hộ công khai của bạn giúp chúng tôi ưu tiên các tính năng và cho các nhà cung cấp trình duyệt khác thấy tầm quan trọng của việc hỗ trợ các tính năng đó. Gửi một tweet đến @ChromiumDev bằng hashtag #WebOTP và cho chúng tôi biết bạn đang sử dụng ở đâu và như thế nào.

Tài nguyên