iOS에서 WebAuthn 유저 제스처 오류

오류 발생

PWA를 만들면서 FIDO 로그인도 지원하게 되었다. 내가 만든 부분은 아니지만 나는 iOS QA 담당이었기 때문에(아님) iOS에서 패스키 인증 관련 테스트를 계속 해봤다.

인증하기 전에 왠지 좀 떨려서 인증창의 X를 눌러서 닫아버렸다. 다시 버튼을 클릭했을 때는, 패스키 등록 창이 다시 뜨지 않았다..

 User gesture is not detected

iOS에서 인증도중 취소하고, 재시도 할 경우 User gesture is not detected 에러가 발생.

iOS에서 정책상의 이유로 credentials.create, get 등으로 WebAuthn을 사용할 때, User gesture 이벤트인 ‘click’, ‘touchend’, ‘doubleclick’, ‘keydown’ 에 해당하는 이벤트에서 실행해야만 동작한다. 해당하는 이벤트로 실행하지 않아서 거절했다는 뜻.

다른 FIDO 오픈된 예시에 가서 똑같이 취소 후 다시 호출을 해봤다. 다른 예시들에서 잘 됐다. 우리 거만 아이폰에서 에러가 떴다.. 다른게 다 되면 우리 코드가 이상하다는 건데..

왜 우리 거만 안되는지 찬찬히 생각해 보아야했다. 뭐가 다른지를 알아야 고치는데 다른 점을 하나씩 찾는 것도 테스트 하는 것도 막막했다. 헷갈렸던 이유는 첫 시도에는 되고 두 번째 부터는 새로고침해도 안된다는 점이었다. 완전히 앱을 종료하고 다시 들어오면 또 되고, 그 때에도 두 번째 시도부터는 안된다.

일단 기능이 안되는 거는 아니고 취소를 안하거나 앱을 재실행 하면 되기 때문에 우선순위에서는 잠시 밀려나 있었다.

실패했던 해결 시도들

(사실 이거보다 더 다양한 걸 시도했었음)

  1. 인증 취소 시 새로고침. location.reload()로 새로고침을 했다.
  2. button을 disabled 해보고 다시 해제
  3. 인증 실행하면 v-if로 없앴다가, 인증 취소하면 다시 새로 렌더링
  4. 클릭 이벤트 대신에 touchstart, touchend 이벤트 사용해보기

그 외 확인해보거나 시도하려고 했던 것들

  • publicKey 발급 문제인가
  • vue의 문제인가(+ vue의 버전 문제인가)
  • 캐시나 세션의 문제인가
  • 아무튼 코드 문제 ㅠㅠ

아이폰이 아닌 맥북에서 테스트

맥북에 지문 인식이 가능하기 때문에 모바일이 아닌 환경에서는 어떤지 테스트 해봤다.

아이폰에서랑 달리 한번 취소 이후 재시도 하면 허용할것이냐고 묻는 알림창이 뜨고, 허용시 정상적으로 동작했다. 허용 알림창은 우리가 만든게 아닌데 알아서 띄워줬다.

테스트 환경: 맥북 에어 m2, Sonoma 베타 버전, Dock에 추가(아이폰에서 pwa 추가하는 방식이랑 비슷) 방법으로 앱 설치를 해서 테스트

⇒ 지금 생각해 보니 최근 Sonoma 버전에서는 유저 제스처 추적이 강화(?) 된 거 같다. 작업중인 인텔맥북에는 지문 인식 그.. 터치아이디 버튼이 없어서 테스트 못 해봤다.

iOS의 user gesture 없음 에러

일단은 에러 메세지를 제대로 파악하는 데로 돌아왔다. 검색을 해보니 예전에는 iOS에서 유저 제스처가 전파가 안됐던거 같다. 현재 코드를 보니 비동기로 하는게 많아서 그 중간에 어딘가에서 유저 제스처를 잃어버린 것 같다고 판단했다.

예전의 사파리 사례 1, 예전의 사파리 사례 2

해결 방법

기존의 코드 흐름

  1. 사용자가 버튼을 클릭
  2. 로그인 함수 실행
    1. 필요한 인증 정보를 불러온다.
    2. 이후 navigator.credentials.get 으로 인증창을 띄운다.

유저의 클릭이 바로 navigator.credentials.get 호출로 이어질 수 있도록 그 전에 있었던 비동기 코드를 분리하는 일이 필요했다. navigator.credentials.get 호출 이전에 필요한 인증 정보를 불러와야 했는데 그분을 로그인 페이지 진입할 때 미리 로드해 두었다.

수정한 코드 흐름

  1. 로그인 페이지 진입할 때 필요한 정보를 로드
  2. 생체인증 로그인 버튼을 누르면 바로 navigator.credentials.get 을 실행
  3. 취소 혹은 실패가 되었을 때는 인증 정보를 다시 로드 했다.
  4. 이후 다시 생체인증 로그인 버튼을 누르면 navigator.credentials.get 이 정상적으로 실행되면서 인증창이 다시 열린다.

적용 후

막상 적용해보니 엄청 편리하다. 이전에는 아이폰의 기본 패스키 기능을 사용했지만, 이제 편리함은 둘이 비슷해진 느낌. 다른 점이라면 패스키는 사용자가 직접 설정하면 되지만, WebAuthn은 제품을 만드는 쪽에서도 처리를 해줘야 하는 점. 사용자가 좀 더 간편하게 로그인 할 수 있어서 접근성이 높아진 것 같다.

Leave a comment