👨💻 이 글을 작성한 이유
신규 서비스와 연동해야 하는 상황이었다.
신규 서비스는 팝업 형태로 로그인 페이지를 제공하고, 기존 서비스와 데이터를 주고 받아야 했다.그런데, 요즘 웹 트렌드에서는 팝업을 잘 사용하지 않다 보니 참고할 만한 자료가 적었고, 이로 인해 여러 시행착오를 겪었다. 이 글은 그 때의 경험을 정리해두면, 비슷한 상황에 처한 분들에게 도움이 될 것 같아 작성하게 되었다.
요구조건
공채 사이트
에서지원서 작성
을 눌렀을 때수상시 채용 서비스 로그인 창
은 팝업 형태로 떠야 한다. (추후에 팝업이 아닌 새 창으로 열리고 그 새창에서 공채 사이트의 이력서 페이지를 redirect하는 식으로 바뀌게 된다. 이유는 크롬 브라우저 정책인 팝업 차단 때문이다.)수상시 채용 서비스 로그인 창
에서 로그인 성공 시 지원서를 작성할 수 있는이력서 페이지
가 열리면서 수상시 채용 서비스에 API를 요청해서 회원 정보를 받아야 함으로 accessToken을 전달받아야 하고 이 때로그인 팝업 창
은 닫혀야 한다. (이 요구사항 역시, 팝업 차단의 문제가 있어서 redirect하는 식으로 바뀌었고 accessToken을 query에 넣어 전달하는 형식으로 바꿨다. 그리고 일반적으로 공채 서비스 쪽 백엔드를 거쳐서 수상시 채용 서비스쪽 백엔드로 요청하는 것이 맞으나, 이 때 당시 잦은 기획 변경으로 촌각을 다투고 있는 상황이었기에 불가피했다.)이력서 페이지
로 다이렉트로 접근 시공채 사이트
로 돌려보낸다.이력서 페이지
에서 쿼리가 없을 경우에는 어떤 공고인지 모르는 상태기 때문에 공고 SelectBox에서 공고를 선택할 수 있어야 하며, 공고를 선택하면수상시 채용 서비스 로그인 창
이 팝업 창으로 열리고 로그인 성공 시 팝업 창이 종료되면서 사용자 정보를 받아온다. (첫번째 요구조건에서는 추후 새 창으로 뜨도록 방향을 바꿨지만, 이 요구사항의 경우에는 현재 페이지를 유지해야하기 때문에 팝업 창을 사용했다.)
시행착오
초기에 시도했던 흐름(팝업 중심)과 최종적으로 성공한 리다이렉트 방식을 정리해보았다.
첫 번째 시도
초기 기획대로 수상시 채용 사이트 로그인 팝업에서 로그인을 완료하면, 공채 사이트가 메시지를 받아 새 창을 열어 [이력서 작성 페이지]로 이동시키고자 했다.
// 공채 사이트 - 공고 페이지
// [지원서 작성] 버튼을 누르면 수상시 채용 서비스의 로그인 팝업창을 연다.
const loginPopup = window.open('...', '_blank')
// 로그인 팝업에서 메시지가 오길 기다린다
window.addEventListener('message', (e) => {
const {data: {accessToken}, origin} = e;
if(origin !== '수상시 채용 서비스') return;
// 로그인에 성공하면 기존 로그인 팝업창을 닫고, 새 페이지를 오픈한다.
loginPopup.close();
// 새 페이지를 오픈하는 로직 -> 문제 지점
})
// 수상시 채용 사이트
if(로그인 성공 시) {
window.opener.postMessage({ accessToken }, '공채 사이트 도메인')
}
결과 및 문제점
-
accessToken을 받은 뒤 곧바로 [이력서 작성 페이지]를 새 창으로 열려 했는데, 이는 사용자 클릭 이벤트로 열린 것이 아닌 JS 스크립트에 의해 열리는 창이어서 브라우저 팝업 차단이 발생했다.
-
팝업 차단을 안내하는 모달(“팝업을 허용해주세요”)을 띄워서 사용자가 직접 허용하도록 유도했으나, 결국 기획에서 “팝업 차단이 아예 안 뜨게 해달라”는 요청이 들어왔다.
두 번째 시도
첫 번째 시도처럼 공채 사이트에서 Javascript에 의해 새 창을 여는 게 문제이므로, 아예 수상시 채용 서비스 로그인 창(팝업)에서 로그인 버튼을 클릭하는 순간 [지원서 작성 페이지]를 직접 열어주는 방식을 고민했다.
// 이제 더 이상 공채 사이트에서 지원서 작성 페이지를 열지 않는다.
// 지원서 작성 페이지의 주소와 세션 정보를 한번에 넘긴다.
window.open('로그인 페이지 + 로그인 성공 시 열어야 할 지원서 작성 페이지 + 세션정보', '_blank');
// 수상시 채용 사이트
if(로그인 성공 시) {
newPage = window.open('');
}
window.addEventListener('message', (e) => {
const {data, origin} = e;
if(origin !== '..') return;
newPage.postMessage(accessToken, originUrl);
})
// 공채 사이트 - 이력서 작성 페이지
window.opener.postMessage('im open! give me accessToken!', originUrl);
window.addEventListener('message', (e) => {
const {data: {accessToken}, origin} = e;
if(origin !== '..') return;
sessionStorage.setItem('accessToken', accessToken);
window.opener.close();
})
결과
-
처음 로그인 시에는 이 흐름이 잘 동작했다. 사용자가 직접 [지원서 작성]을 클릭해서 팝업을 열었고, 팝업 페이지에서도 로그인을 클릭하는 순간 window.open이 동작하므로 팝업 차단이 발생하지 않았다.
-
하지만, 이미 로그인된 상태에서 문제가 발생했다. 이 경우에는 “사용자 클릭 이벤트 → 팝업 열기” 순서가 아닌 “스크립트가 알아서 팝업 열기”가 되어버려 또다시 팝업 차단이 발생했다.
-
뿐만 아니라 브라우저별 동작 차이, 교차출처 문제 등으로 인해 팝업/자식창 제어가 뒤얽히면서 예상치 못한 문제가 자주 생겼다.
팝업 자체가 UX 면에서도 부담이 컸고, 복합적으로 더 큰 문제가 될 수 있음을 실감했다.
세 번째 시도
최종적으로 리다이렉트 방식을 사용하기로 했다.
- 로그인 페이지는 팝업이 아닌 완전히 새 창으로 열리고, 로그인 성공 시 바로 [지원서 작성 페이지]로 리다이렉트한다.
- accessToken은 URI 쿼리에 실어 전달한다. (다른 도메인이므로 localStorage나 sessionStorage를 직접 공유할 수 없음)
결과
-
팝업 차단 이슈가 사라졌다.
-
accessToken이 URL에 노출되는 것이 좋아 보이진 않았지만, 보안상 문제없음을 확인했다. (HTTPS 사용 및 필요 시 만료 시점 설정 가능)
-
복잡했던 팝업/자식창 제어 로직이 없어지면서 유지보수가 수월해졌다.
후기
-
처음 기획을 그대로 구현하기보다는, 초기에 여러 시나리오와 기술적 제약을 검토하는 시간이 필요함을 절실히 깨달았다.
-
기획 변경 없이 곧바로 팝업을 쓰겠다고 했다가, 결과적으로 시간과 리소스를 더 쏟게 되었다. 위에서 정리한 코드는 극히 일부 상황만 발췌한 것이다. 실제로는 경우의 수가 훨씬 더 많았고, 복잡도도 컸다.
-
플로우차트를 10페이지 이상으로 그리며 개발했는데, 개발자 간 혹은 기획과의 커뮤니케이션 시 큰 도움이 되었다. 팝업은 모바일 환경에서 더 치명적이다. 인앱 브라우저 등에서 제대로 동작하지 않는 사례가 많다. 이번엔 PC 위주 개발이라 팝업 시도를 했으나, 모바일까지 고려했다면 더 빠르게 팝업을 포기했을지도 모른다.
-
“지레짐작은 금물”이라는 교훈을 다시금 얻었다. 당연히 accessToken은 URL에 넣으면 안 될 줄 알았는데, 확인해보니 보안상 큰 문제가 없었다. 애매한 부분이 있으면 끝까지 의심해보고, 정확한 근거를 확보하는 태도가 중요하다.