web
NICE 본인인증 구현시 프론트엔드에서 postMessage 활용방안

NICE 본인인증 구현시 프론트엔드에서 postMessage 활용방안

상황

NICE 본인인증 팝업을 통해 인증이 완료된 유저만 접근가능하도록 하는 기능이 필요했다. 백엔드 개발자분께서 NICE측 API (opens in a new tab)을 활용해 백엔드 로직은 완료해주셨고, 내가 해야할 일은 다음과 같았다.

  • 공식문서에서 제공해주는 form 코드를 통해 인증 팝업을 연다.
  • 팝업이 닫히는 이벤트를 감지하고, 인증 이후 분기처리를 실행한다.

문제

NICE인증 팝업을 사용하는 측에서 어떻게 인증이 완료됨을 알 수 있을까?

beforeunload - window가 닫힐 때 발생하는 이벤트

해당 이벤트를 사용해서 인증 성공 여부와 상관없이 팝업이 닫히면 현재 계정의 인증 여부를 조회하는 API를 호출하려고 했음.

popUpRef.current = window.open(...)
popUpRef.current?.addEventListener('beforeunload', () => {
  ...
});

왜 인지 이벤트가 팝업이이 닫힐 때가 아니라, 팝업이 열릴 때 바로 트리거됐다.

확인해보니 window.open 해서 열었던 주소가 same site policy를 만족하지 못해서였다. 같은 호스트거나 서브 도메인이면 가능하다.

window.postMessage - window 오브젝트 간 cross-origin 통신을 안전하게 할 수 있게해주는 메소드

한 쪽 window에서 해당 메서드를 통해 메시지를 발신하면 다른쪽에선 이벤트 리스너로 수신할 수 있게해준다. 이를 활용해서 사용하는 곳에서 message를 받으면 인증에 성공한 것으로 간주, 인증여부를 조회하는 API를 invalidation하려했다.

/*
 * <http://example.com:8080>에 있는 윈도우 A의 스크립트:
 */
 
var popup = window.open(...popup details...);
 
// 팝업이 완전히 로드되었을 때:
popup.parent.postMessage("hello there!", "http://example.com");
 
function receiveMessage(event)
{
 
  if (event.origin !== "http://example.com")
    return;
 
  // console.log(event.data); "hello there!"
}
window.addEventListener("message", receiveMessage, false);

역시나 한번에 동작하지 않았다...

window.parent vs window.opener

window.opener refers to the window that called window.open( ... ) to open the window from which it's called window.parent refers to the parent of a window in a <frame> or <iframe>

[출처] (opens in a new tab)

window.opener를 사용했어야했는데 parent를 사용했기 때문에 메시지를 수신할 수 없었다. 근데 window.opener로 변경해도 메시지가 수신되지 않았다..

cross domain 간 postMessage로 통신할 때 두번째 파라미터인 targetOrigin을 설정해주지 않아 수신할 수 없었던 것이다. 위 예시처럼 postMessage 두번째 매개변수에 호스트를 추가해서 해결했다.

* 로 설정하면 모든 호스트에 대해 허용인데, 이는 보안상 쓸모없는 설정이다. 다만 개발 환경에선 localhost, 개발서버 URL 모두 허용해줘야하기 때문에 * 설정하고 운영에선 정상적인 origin을 설정했다.