WebOTP API로 웹에서 전화번호 인증

SMS를 통해 수신된 OTP로 사용자 지원하기

Eiji Kitamura
Eiji Kitamura

WebOTP API란 무엇인가요?

요즘에는 전 세계 대부분의 사람들이 휴대기기를 소유하고 있으며 개발자는 일반적으로 전화번호를 서비스 사용자의 식별자로 사용합니다.

전화번호를 인증하는 방법에는 여러 가지가 있지만 SMS로 전송되는 무작위로 생성된 일회용 비밀번호 (OTP)가 가장 일반적입니다. 이 코드를 개발자의 서버로 다시 전송하면 전화번호를 제어할 수 있음을 나타���니다.

이 아이디어는 다음을 달성하기 위해 이미 여러 시나리오에 배포되어 있습니다.

  • 사용자 식별자로서의 전화번호 일부 웹사이트에서는 새 서비스에 가입할 때 이메일 주소 대신 전화번호를 요청하고 이를 계정 식별자로 사용합니다.
  • 2단계 인증 로그인할 때 웹사이트에서 추가 보안을 위해 비밀번호 또는 기타 지식 계정 외에도 SMS를 통해 전송된 일회용 코드를 요청합니다.
  • 결제 확인. 사용자가 결제할 때 SMS를 통해 전송되는 일회용 코드를 요청하면 사용자의 의도를 확인하는 데 도움이 될 수 있습니다.

현재 절차는 사용자에게 불편을 끼칩니다. SMS 메시지에서 OTP를 찾은 다음 양식에 복사하여 붙여넣는 작업은 번거로우며 중요한 사용자 여정에서 전환율을 낮춥니다. 이 문제를 완화하기 위한 요구는 오랫동안 전 세계 주요 개발자들로부터 제기되어 왔습니다. Android에는 이 작업을 정확하게 실행하는 API가 있습니다. iOSSafari도 마찬가지입니다.

WebOTP API를 사용하면 앱이 앱의 도메인에 바인딩된 특별한 형식의 메시지를 수신할 수 있습니다. 이를 통해 SMS 메시지에서 OTP를 프로그래매틱 방식으로 가져와 사용자의 전화번호를 더 쉽게 확인할 수 있습니다.

실제 사례 보기

사용자가 웹사이트에서 전화번호를 인증하려고 한다고 가정해 보겠습니다. 웹사이트에서 SMS를 통해 사용자에게 문자 메시지를 보내면 사용자는 메시지의 OTP를 입력하여 전화번호 소유권을 확인합니다.

WebOTP API를 사용하면 동영상에 설명된 대로 사용자가 한 번 탭하기만 하면 됩니다. 문자 메시지가 도착하면 하단 시트가 표시되고 사용자에게 전화번호를 인증하라는 메시지가 표시됩니다. 하단 시트에서 Verify(확인) 버튼을 클릭하면 브라우저가 OTP를 양식에 붙여넣고 사용자가 Continue(계속)를 누르지 않아도 양식이 제출됩니다.

전체 프로세스는 아래 이미지에 다이어그램으로 표시되어 있습니다.

WebOTP API 다이어그램

데모를 직접 사용해 보세요. 전화번호를 묻거나 기기에 SMS를 보내지 않지만, 데모에 표시된 텍스트를 복사하여 다른 기기에서 SMS를 보낼 수 있습니다. 이는 WebOTP API를 사용할 때 발신자가 누구인지 중요하지 않기 때문에 작동합니다.

  1. Android 기기의 Chrome 84 이상에서 https://web-otp.glitch.me으로 이동합니다.
  2. 다른 휴대전화에서 내 휴대전화로 다음 SMS 메시지를 보냅니다.
Your OTP is: 123456.

@web-otp.glitch.me #12345

SMS를 수신하고 입력 영역에 코드를 입력하라는 메시지가 표시되었나요? WebOTP API는 사용자에게 이렇게 작동합니다.

WebOTP API 사용은 다음 세 부분으로 구성됩니다.

  • 올바르게 주석 처리된 <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는 간단하므로 다음 코드를 복사하여 붙여넣기만 하면 됩니다. 어떤 일이 일어나고 있는지 안내해 드리겠습니다.

자바스크립트

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 트리를 쿼리할 준비가 될 때까지 기다립니다.

자바스크립트

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'이 포함된 배열이어야 합니다.

자바스크립트

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

이렇게 하면 SMS 메시지가 수신될 때 브라우저의 권한 흐름이 트리거됩니다. 권한이 부여되면 반환된 프로미스는 OTPCredential 객체로 확인됩니다.

획득한 OTPCredential 객체의 콘텐츠

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

그런 다음 OTP 값을 <input> 필드에 전달합니다. 양식을 직접 제출하면 사용자가 버튼을 탭해야 하는 단계가 없어집니다.

자바스크립트

    …
    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를 위한 마지막 줄을 남깁니다.
  • 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을 방문하여 신용카드로 신발 한 켤레를 구매합니다.
  • 신용카드 번호를 입력하면 통합 결제 제공업체에서 빠른 결제를 위해 사용자에게 전화번호를 인증하라는 메시지가 표시된 bank.example의 양식을 iframe 내에 표시합니다.
  • bank.example는 사용자가 OTP를 입력하여 신원을 확인할 수 있도록 OTP가 포함된 SMS를 사용자에게 전송합니다.

교차 출처 iframe 내에서 WebOTP API를 사용하려면 다음 두 가지를 실행해야 합니다.

  • SMS 텍스트 메시지에서 상단 프레임 출처와 iframe 출처를 모두 주석 처리합니다.
  • 교차 출처 iframe이 사용자로부터 OTP를 직접 수신할 수 있도록 권한 정책을 구성합니다.
iframe 내에서 작동하는 WebOTP API

https://web-otp-iframe-demo.stackblitz.io에서 데모를 사용해 볼 수 있습니다.

SMS 문자 메시지에 bound-origins 주석 추가

WebOTP API가 iframe 내에서 호출되면 SMS 문자 메시지에는 @로 시작하는 최상위 프레임 출처, #로 시작하는 OTP, 마지막 줄에 @로 시작하는 iframe 출처가 포함되어야 합니다.

Your verification code is 123456

@shop.example #123456 @bank.exmple

권한 정책 구성

교차 출처 iframe에서 WebOTP를 사용하려면 삽입자가 의도치 않은 동작을 방지하기 위해 otp-credentials 권한 정책을 통해 이 API에 대한 액세스 권한을 부여해야 합니다. 일반적으로 이 목표를 달성하는 방법에는 두 가지가 있습니다.

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 계정으로 로그인해야 합니다.

개발자는 모바일 웹사이트에서 하는 것과 동일한 방식으로 데스크톱 웹사이트에 WebOTP API를 구현하기만 하면 되며 특별한 트릭은 필요하지 않습니다.

WebOTP API를 사용하여 데스크톱에서 전화번호 인증에서 자세한 내용을 알아보세요.

FAQ

올바른 형식의 메시지를 보내는데도 대화상자가 표시되지 않습니다. 이유가 무엇일까요?

API를 테스트할 때는 몇 가지 주의사항이 있습니다.

  • 발신자의 전화번호가 수신자의 연락처 목록에 포함된 경우 기본 SMS 사용자 동의 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 구현에서 버그를 발견했나요?

  • crbug.com에서 버그를 신고합니다. 최대한 자세하게 작성하고 재현을 위한 간단한 안내를 포함하고 구성요소Blink>WebOTP로 설정합니다.

이 기능을 개선하기 위해 어떻게 도와드릴 수 있나요?

WebOTP API를 사용할 계획인가요? 공개적으로 지원해 주시면 기능의 우선순위를 정하는 데 도움이 되며 다른 브라우저 공급업체에게 이를 지원하는 것이 얼마나 중요한지 보여줍니다. #WebOTP 해시태그를 사용하여 @ChromiumDev에 트윗을 보내고 사용 빈도와 사용 방법을 알려주세요.

리소스