mWiSE 프로젝트에서 React Native에서 react-native-webview를 사용하다가 "버그? 에러?"라고 생각한 순간이 있었다.
상황을 요약하면
React Native앱에서 react-native-webview 사용
WebView로 로그인 페이지 진입
로그인 성공 시 서버에서 Set-Cookie로 인증 토큰 전달
여기까지 정상
문제는 아래 코드 라인에서 시작되었다.
// RN
axios.get('/api/some-resource');RN에서 header에 따로 쿠키 설정을 하지 않았고
RN에서 따로 로그인을 한 적도 없었고(WebView에서 로그인)
axios config 로그르 찍어도 cookie가 없었다.
그런데도 서버에서는 계속
"인증된 사용자로 요청이 들어옴"
처음에는 도저히 납득이 안돼서 버그라고 생각했다.
그래서 당연히 401이 떨어질 줄 알았는데, 서버 로그에는 정상적으로 쿠키가 전달되고 있었다.
인프라팀이랑 같이 패킷을 보고, 서버 설정도 전부 확인했는데 서버 쪽 문제는 전혀 아니었다. (사실 nginx 문제이기를 기도했다).
하지만 구글링을 하다가 아래 코드로 테스트를 진행했다.
<WebView
incognito={true}
source={{ uri: loginUrl }}
/>이렇게 진행하니 WebView 로그인 후 → RN 네이티브에서 axios(fetch) 요청 시 → 쿠키 전달 안됨
여기서 WebView와 Native가 쿠키를 공유하고 있다는 확신이 들었다.
나의 아메리카노 3잔과 밤샘의 결과로 이 현상은 안드로이드에서는 정상 동작이었다.
그 이유는 안드로이드는 WebView와 Native 모두 같은 시스템 쿠키 저장소를 사용한다.
즉 WebView 로그인 → 서버가 Set-Cookie로 전달 → 쿠키는 Android의 CookieManager(Shared Cookie Store)에 저장된다.
이후 React Native에서 같은 도메인으로 네트워크 요청을 보낼경우, 안드로이드 네트워크 스택이 쿠키를 자동으로 붙여서 전송한다.
그리고 내 하루 수면시간을 뺏어간 또 하나의 범인은.
서버에서는 쿠키를 확인할 수 있지만, RN에서 로그를 찍으면 axios.config.headers에는 쿠키가 보이지 않는다.
왜냐하면 axios는 "내가 직접 설정한 header"만 보여주고 실제 쿠키 추가는 안드로이드 OS 레벨에서 백그라운드로 처리되기 때문이다.
하지만 더 웃기는 포인트는 iOS는 적용되지 않는다는 점이다.
iOS의 WKWebView와 NSURLSession는 기본적으로 쿠키 저장소를 공유하지 않는다.
그래서 같은 코드를 사용해도 안드로이드는 쿠키가 전달되고, iOS는 쿠키가 전달되지 않았다.
그 결과 플랫폼별로 인증 Flow가 다르게 느껴졌다.
이 상황을 팀장님 및 인프라팀에 전달한 후, 이게 좋은건지 나쁜건지 정확히 판단하기 어려웠다.
하지만 이 이슈를 처음에 접했을 때의 첫인상은 "위험하다"였다.
보안 모델을 명확하게 이해하지 못한 상태에서 WebView를 무의식적으로 "격리된 공간"으로 생각하면, 의도치않게 인증 정보가 Native 영역과 공유될 수 있고 그건 문제가 될 소지가 있다.
이런 구조를 모르고 사용한다면 나의 경우처럼 "로그인은 WebView에서 했는데 왜 Native API가 인증되는 상황"을 맞이할 수 있다.
만약 WebView와 Native 영역의 인증을 명확하게 분리하고 싶다면, incognito를 사용하자.
개발 브랜치 커밋 이후, 몸으로 부딪혀야 직성이 풀리기 때문에 아래의 순서로 찾아봤다.
1. 깃허브에 이슈
이해가 안되면 일단 공식 저장소부터 가는게 맞다고 생각했다. 이슈를 남겼다.
2. Stack Overflow
내가 기본적인걸 놓쳤는지 궁금해서 질문을 남겼다.
nice한 Abdul_Basit이 답변을 남겨주었다.
3. 직접 테스트
그래도 회사 프로젝트에서만 발생하는 문제인가 싶어서 [서버 + 웹뷰 로그인 페이지 + ReactNative 앱]으로 구성된 최소한의 프로젝트를 만들어서 테스트해봤다.
그 결과 안드로이드에서는 이 현상이 일관되게 재현되었다.
(궁금하시면 이 레포로 테스트 해보시기 바랍니다)
끝