앱 개발

웹뷰에서 카카오/구글 OAuth가 안 되는 이유, 구조부터 짚어드립니다

"PC에선 잘 되는데 앱에서만 흰 화면이 떠요"라는 문의가 정말 많아요. 웹뷰 앱 만들 때 가장 자주 부딪히는 문제 중 하나입니다. 단순히 코드 추가의 문제가 아니라 OAuth 표준과 모바일 OS의 충돌이라는 구조적 이슈예요. 본질부터 짚으면 해결도 쉬워집니다.

7분 소요

DEEP DEBUG

웹뷰에서 카카오/구글 OAuth가 안 되는 이유, 구조부터 짚어드립니다

"PC에선 잘 되는데 앱에서만 흰 화면이 떠요"라는 문의가 정말 많아요. 웹뷰 앱 만들 때 가장 자주 부딪히는 문제 중 하나입니다. 단순히 코드 추가의 문제가 아니라 OAuth 표준과 모바일 OS의 충돌이라는 구조적 이슈예요. 본질부터 짚으면 해결도 쉬워집니다.

결론을 미리 말씀드리면, 이 문제의 근본 원인은 "웹뷰는 외부 앱(카카오톡)을 직접 실행할 권한이 없다"는 데 있습니다. PC 브라우저는 이걸 자동 처리하지만, 모바일 웹뷰는 명시적으로 코드를 추가해야 처리돼요. 그래서 PC는 되는데 앱은 안 되는 거예요.

또한 구글은 2021년부터 보안 이유로 웹뷰의 OAuth 사용을 공식적으로 제한합니다. 즉, 카카오와 구글은 다른 차원의 문제예요. 카카오는 처리 코드 추가로 해결되지만, 구글은 Chrome Custom Tabs로 우회해야 합니다. 이 차이를 모르고 같은 방식으로 접근하면 구글 로그인은 절대 작동 안 해요.

참고로 이 모든 처리(intent URL 핸들링, window.open 처리, Custom Tabs 전환, 네이티브 SDK 연동)가 이미 내장된 웹뷰 앱 솔루션도 있습니다. 직접 다 짜는 게 부담스러우시면 앱박스 같은 솔루션으로 시작하시는 것도 한 방법이에요. 본문은 직접 구현하는 분들을 위한 가이드입니다.

먼저 OAuth 흐름이 웹뷰에서 어떻게 깨지는지

PC 브라우저와 모바일 웹뷰의 OAuth 흐름 차이를 보면 문제의 본질이 보입니다. 같은 OAuth 표준인데 왜 모바일에서만 깨지는지 이해되실 거예요.

OAuth 흐름의 차이
PC 브라우저 ✓
1. 카카오 로그인 버튼 클릭

2. 카카오 인증 페이지 호출

3. 인가코드 → redirect URI 리턴

로그인 성공
모바일 웹뷰 ✗
1. 카카오 로그인 버튼 클릭

2. intent:// URL 호출 시도
(카카오톡 앱 실행)

웹뷰는 intent URI 처리 불가
웹뷰는 외부 앱 실행 권한 없음
→ 흰 화면

핵심은 2번 단계예요. 카카오 SDK는 카카오톡 앱을 실행하기 위해 intent:// URL scheme을 호출하는데, 웹뷰는 기본적으로 이런 URL을 처리하는 권한이 없습니다. 그래서 클릭해도 아무 일도 안 일어나거나 흰 화면만 떠요.

이걸 해결하려면 웹뷰의 URL 처리 로직을 직접 오버라이드해서 "intent:// URL이 오면 외부 앱을 실행하도록" 명시적으로 코드를 추가해야 합니다. 그래서 카카오는 공식 문서에서 두 가지 작업을 안내해요.

카카오 OAuth 해결법: 두 가지 작업

카카오 측에서 명시한 해결책은 "카카오톡 실행 처리""팝업 웹뷰 처리" 두 가지를 모두 추가하는 것입니다. 둘 중 하나만 하면 부분적으로만 작동해요.

작업 1: 카카오톡 앱 실행 처리 (Android)

웹뷰의 shouldOverrideUrlLoading 메서드를 오버라이드해서, intent URI가 호출되면 직접 파싱해 카카오톡 앱을 실행해야 합니다.

// Android Kotlin 예시
override fun shouldOverrideUrlLoading(
  view: WebView, request: WebResourceRequest
): Boolean {
  val url = request.url.toString()
  if (url.startsWith("intent://")) {
    val intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME)
    view.context.startActivity(intent)
    return true
  }
  return false
}
주의: 카카오톡이 설치 안 된 기기에서는 ActivityNotFoundException이 발생합니다. try-catch로 감싸서 미설치 시 카카오 계정 로그인 페이지로 fallback 처리 필수예요. 안 그러면 앱이 죽어요.

작업 2: 팝업 웹뷰 처리 (window.open)

카카오 JavaScript SDK는 보안 향상을 위해 일부 기능에서 팝업 윈도우를 사용합니다. 웹뷰가 window.open()을 처리하지 못하면 클릭해도 아무 일도 안 일어나요. 이게 두 번째 사고 지점입니다.

// 부모 웹뷰 설정
webView.settings.run {
  javaScriptEnabled = true
  javaScriptCanOpenWindowsAutomatically = true
  setSupportMultipleWindows(true) // 핵심!
}
 
// onCreateWindow에서 자식 웹뷰 생성
override fun onCreateWindow(...): Boolean {
  val childWebView = WebView(view.context)
  // 부모와 동일한 설정 적용
  // transport.webView = childWebView
  // resultMsg.sendToTarget()
  return true
}

iOS WKWebView 처리

iOS는 Android와 메서드 이름만 다를 뿐 처리 원리는 동일합니다. decidePolicyFor navigationAction에서 URL scheme 분기.

// iOS Swift 예시
func webView(_ webView: WKWebView,
  decidePolicyFor navigationAction: WKNavigationAction,
  decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
  guard let url = navigationAction.request.url else { return }
  if url.scheme == "kakaotalk" || url.scheme == "kakaolink" {
    UIApplication.shared.open(url)
    decisionHandler(.cancel)
    return
  }
  decisionHandler(.allow)
}
여기까지 보시고 "이걸 안드로이드, iOS 양쪽에서 다 짜고 유지보수까지 해야 하나..." 싶으시다면 정상입니다. 저도 처음엔 그랬어요. 시간 아끼고 싶으시면 이런 처리를 자동으로 해주는 웹뷰 앱 빌더 솔루션을 검토해보시는 것도 합리적인 선택입니다.

구글 OAuth는 다릅니다: Chrome Custom Tabs로 우회

카카오는 위 처리로 해결되지만, 구글은 다른 차원의 문제입니다. 구글은 2016년부터 보안 이유로 웹뷰에서의 OAuth 사용을 공식적으로 제한해왔고, 2021년부터는 점차 차단을 강화하고 있어요.

⚠️ 구글의 공식 입장
구글 측 메시지: "WebView에서 인증에 OAuth를 사용하면 앱이 보안 문제에 취약해질 수 있으며, 싱글 사인온(SSO) 세션에서 사용자의 연결이 끊겨 사용성이 저하될 수 있습니다."
구글의 권고: Chrome Custom Tabs(Android) / SFSafariViewController(iOS)로 교체하세요.

Chrome Custom Tabs는 웹뷰가 아니라 진짜 Chrome 브라우저예요. 사용자의 기존 구글 로그인 세션을 그대로 활용할 수 있고, 보안 표준도 만족합니다. 화면 전환은 거의 자연스럽게 보이고요.

Android Custom Tabs 사용 예시:

// 구글 OAuth는 웹뷰 대신 Custom Tabs로
val customTabsIntent = CustomTabsIntent.Builder()
  .setShowTitle(true)
  .build()
customTabsIntent.launchUrl(context,
  Uri.parse("https://accounts.google.com/o/oauth2/v2/auth?..."))

실전 디버깅: 흰 화면 만났을 때 체크 순서

실제로 트러블슈팅 할 때의 체크 순서입니다. 위에서부터 차례로 확인하세요. 5분 안에 원인 90%는 잡힙니다.

STEP 1
Chrome inspect로 웹뷰 디버깅 활성화
Android는 chrome://inspect로 실제 웹뷰 콘솔 로그 확인 가능. iOS는 Safari → 개발 메뉴. 흰 화면의 99%는 콘솔에 에러 메시지가 있어요. 콘솔 안 보고 추측하면 시간만 낭비됩니다.
STEP 2
Network 탭에서 redirect 흐름 추적
로그인 클릭 → 카카오 → redirect URI까지 어디서 끊기는지 확인. intent:// 호출 시점에서 멈췄다면 shouldOverrideUrlLoading 미구현. URL이 끊긴 지점 = 문제 발생 지점.
STEP 3
redirect URI가 카카오 콘솔에 등록됐는지
"KOE006" 에러 → redirect URI 미등록. 카카오 디벨로퍼스 콘솔의 카카오 로그인 → 리다이렉트 URI에 정확한 값 등록. 콘솔 등록 값과 코드의 redirect_uri가 한 글자도 다르면 안 됩니다.
STEP 4
window.open 처리가 됐는지 확인
팝업 화면 클릭 시 화면이 안 뜨면 setSupportMultipleWindows(true) 누락. Android는 onCreateWindow 오버라이드 필수.
STEP 5
User-Agent 확인 (구글의 경우)
"disallowed_useragent" 에러 → 구글이 웹뷰를 감지하고 차단한 것. Custom Tabs로 전환 외엔 우회 방법 없음.

자주 만나는 에러 코드 빠른 참조

실전에서 자주 만나는 에러 코드와 의미를 정리했어요. 에러 메시지에 이 코드가 보이면 즉시 해결 방향을 잡을 수 있어요.

코드
제공자
의미와 해결
KOE006
카카오
redirect URI 불일치 → 콘솔 등록 확인
KOE101
카카오
앱 키 오류 → REST API 키 확인
KOE237
카카오
요청 수 초과 → Rate limit 정책 확인
disallowed_useragent
구글
웹뷰에서 차단 → Custom Tabs 전환 필수
redirect_uri_mismatch
구글
콘솔 redirect URI 미등록 → GCP 콘솔 확인
access_denied
공통
사용자가 동의 거부 → 정상 흐름

웹뷰 OAuth의 근본적 대안: 네이티브 SDK 직접 사용

사실 가장 깔끔한 해결책은 웹뷰에서 OAuth를 처리하지 않고, 네이티브 SDK로 처리한 토큰을 웹뷰에 전달하는 방식입니다. 구조가 살짝 복잡해지지만 한 번 만들어두면 이후 OAuth 정책 변화에 흔들리지 않아요.

흐름:
1. 웹뷰 → 네이티브 (JavaScript Bridge로 "로그인 시작" 신호)
2. 네이티브 → 카카오 / 구글 SDK로 OAuth 처리
3. 네이티브가 access_token / 사용자 정보 받음
4. 네이티브 → 웹뷰 (토큰 전달, evaluateJavaScript)
5. 웹뷰가 토큰으로 자체 서버에 로그인 처리
장점: 웹뷰 OAuth의 모든 문제(intent URL, window.open, 구글 차단)에서 자유로움. 사용자 경험도 가장 자연스러움. 카카오톡이 설치된 사용자는 SSO도 가능.
단점: JavaScript Bridge 통신 코드 추가 필요. iOS / Android 양쪽 동일하게 구현해야 함. 기존 웹 코드 일부 수정 필요.
DEVELOPER NOTE
이 "네이티브 SDK + JavaScript Bridge" 구조는 사실 직접 구현하면 양쪽 OS 코드만 수백 줄 됩니다. 이런 구조가 이미 패키징된 솔루션을 쓰는 것도 방법인데, 한국 환경에서는 앱박스가 카카오/네이버 로그인, 푸시 알림, 인앱 결제 같은 한국 시장 특화 기능을 SDK 형태로 제공합니다. 자체 개발이 부담스러우시면 한 번 살펴보실 만해요.

정리하며

웹뷰 OAuth 문제의 본질은 "브라우저는 자동으로 처리하지만 웹뷰는 명시적으로 처리해야 한다"는 점입니다. 이걸 알면 모든 트러블슈팅이 쉬워져요. PC에서 잘 되니까 코드 문제가 없을 거라고 생각하면 안 돼요. 모바일 웹뷰는 PC 브라우저와 다른 환경입니다.

제가 가장 강조하고 싶은 건 이거예요. 카카오는 처리, 구글은 우회입니다. 카카오는 위에서 설명한 두 가지 처리(intent 처리, window.open 처리)로 해결되지만, 구글은 Custom Tabs 외에는 답이 없어요. 같은 방식으로 접근하면 시간만 낭비합니다.

한 가지 팁을 더 드리면, 앱 시작부터 네이티브 SDK + JavaScript Bridge 구조로 가시면 위 모든 고민이 사라집니다. 처음에는 약간 복잡해 보이지만, 1년 후 OAuth 정책 변화에 흔들리지 않는 견고한 구조가 돼요. 웹뷰 + OAuth는 어차피 임시방편이라는 점, 인지하고 시작하시는 게 좋습니다.

SHORTCUT
이 모든 처리가 SDK 두세 줄로 끝나는 솔루션
카카오/네이버/구글 로그인, 푸시 알림, 카메라, 생체 인증까지
한국 환경에 최적화된 웹뷰 앱 빌더 솔루션을 검토해보세요
앱박스 둘러보기 →
WebView OAuth 트러블슈팅 · 시니어 개발자 가이드
앱 개발이 고민되시나요?

기획부터 출시까지, 모바일파트너스가 함께합니다

다른 아티클 살펴보기

웹을 앱으로 만들기, 우리 비즈니스엔 정말 도움이 될까?

"우리 비즈니스에 앱이 정말 필요한가?" 진단부터 업종별 실전 적용까지. 쇼핑몰, 교육, 병원, 커뮤니티 4개 사례로 풀어낸 2026년 웹을 앱으로 만들기 가이드.

웹을 앱으로 만들기, 우리 비즈니스엔 정말 도움이 될까?

"우리 비즈니스에 앱이 정말 필요한가?" 진단부터 업종별 실전 적용까지. 쇼핑몰, 교육, 병원, 커뮤니티 4개 사례로 풀어낸 2026년 웹을 앱으로 만들기 가이드.

AI 앱개발, 30일면 이런앱을 개발 할 수 있어요.

"이 앱 만드는데 얼마나 걸려요?" 1년 전 답과 지금 답이 완전히 다릅니다. AI 코딩으로 30일에 가능한 앱과 6주에 가능한 MVP, 라인업으로 정리했습니다

AI 앱개발, 30일면 이런앱을 개발 할 수 있어요.

"이 앱 만드는데 얼마나 걸려요?" 1년 전 답과 지금 답이 완전히 다릅니다. AI 코딩으로 30일에 가능한 앱과 6주에 가능한 MVP, 라인업으로 정리했습니다

[Android] Compose 4년 후, 다시 정리하는 생명주기/상태/렌더링

2022년에 정리했던 Compose 가이드를 4년 만에 다시 씁니다. 무엇이 그대로고 무엇이 바뀌었는지, 주니어가 중급으로 넘어갈 때 꼭 알아야 할 변화를 회고와 함께 정리했어요. 관련 키워드: Jetpack Compose, Compose 생명주기, Compose 상태, Compose 렌더링, Strong Skipping Mode, Composable 최적화, recomposition

[Android] Compose 4년 후, 다시 정리하는 생명주기/상태/렌더링

2022년에 정리했던 Compose 가이드를 4년 만에 다시 씁니다. 무엇이 그대로고 무엇이 바뀌었는지, 주니어가 중급으로 넘어갈 때 꼭 알아야 할 변화를 회고와 함께 정리했어요. 관련 키워드: Jetpack Compose, Compose 생명주기, Compose 상태, Compose 렌더링, Strong Skipping Mode, Composable 최적화, recomposition

모바일파트너스 로고
MobilePartners

(주)모바일파트너즈

서울 마포구 월드컵로 196, 대명비첸시티 14층

Contact

develop@mobpa.co.kr

© 2025 MobilePartners. All rights reserved

모바일파트너스 로고
MobilePartners

(주)모바일파트너즈

서울 마포구 월드컵로 196, 대명비첸시티 14층

Contact

develop@mobpa.co.kr

© 2025 MobilePartners. All rights reserved

모바일파트너스 로고
MobilePartners

(주)모바일파트너즈

서울 마포구 월드컵로 196, 대명비첸시티 14층

Contact

develop@mobpa.co.kr

© 2025 MobilePartners. All rights reserved